返回

Bash路径匹配: 匹配主机名前缀并忽略尾部字符

Linux

Bash 路径匹配:匹配主机名部分并忽略尾部字符

在系统管理和脚本编写中,经常需要根据主机名执行不同的操作。有时,主机名的格式有一定的规律,例如包含一个通用前缀和一些表示特定实例的后缀。当使用 case 语句进行主机名匹配时,就需要设计精确的匹配模式,仅匹配主机名的一部分,并忽略后面的字符。一个常见的错误是使用简单的正则表达式或者通配符,未能正确地捕捉到匹配逻辑,造成匹配失败。 本文将分析这个特定问题,并提供解决方案。

问题分析

脚本使用 case 语句基于主机名进行判断,执行对应的操作。 在例子中,期望主机名以 “presto-data” 开头,后面紧跟数字,并匹配例如 presto-data1-01 这类格式的主机名。使用了扩展的 extglob, 但提供的模式 presto-data+([[:digit:]]) 尝试匹配 “presto-data” 后面至少有一个数字的字符。 问题在于它会匹配 “presto-data1”, 而不是完整的主机名字符串, 同时它也没有处理紧接着的 -01 等后缀字符。 造成了误判,将匹配目标定为 presto-data1 开头的名字, 而不是匹配含有前缀 presto-data 的主机, 所以造成了匹配失败,打印出"Unrecognized hostname"。

解决方案

要解决这个问题,需要在 case 语句中使用正确的 glob 模式,能够匹配 “presto-data” 加上至少一个数字,并且允许忽略后面的任何字符。 下面介绍几种可以实现这个目标的方法。

使用通配符 * 匹配任意字符

最简单的解决方法是使用通配符 *。 通配符 * 可以匹配任何字符 (零个或多个), 包括数字、字母或其他字符。在 presto-data+([[:digit:]]) 后添加 * 表示匹配前缀后面任意字符的组合,能够直接跳过主机名尾部的部分。

#!/usr/bin/env bash
hostname=$(hostname -s)

shopt -s extglob

case $hostname in
    presto+([[:digit:]])*)
       bash /home/presto.sh;;
    presto-data+([[:digit:]])*)
        bash /home/presto-data.sh;;
    *)  echo "Unrecognized hostname $hostname" ;;
esac

步骤:

  1. 将以上代码保存到 /tmp/script.sh 文件。
  2. 给脚本添加执行权限: chmod +x /tmp/script.sh
  3. 执行脚本: /tmp/script.sh

这个修改后的脚本可以正确匹配以 “presto-data” 开头, 紧接着数字, 并且包含任意字符的完整主机名。

使用 ? 通配符精确匹配后缀长度 ( 可选 )

虽然通配符 * 非常方便, 但在某些特定情境下,我们可能希望更加精确的匹配, 而不是跳过所有尾部的字符。 假设后缀字符是类似 [-数字数字] 的格式。 通配符 ? 能匹配任何单个字符, 可以组合 ? 来明确限定后缀的长度。 例如,对于 “-01”, 我们可以使用 *-[[:digit:]][[:digit:]] 来进行更具体的匹配, 限定尾部字符串长度。

#!/usr/bin/env bash
hostname=$(hostname -s)

shopt -s extglob

case $hostname in
    presto+([[:digit:]])-*([[:digit:]]))
       bash /home/presto.sh;;
    presto-data+([[:digit:]])-*([[:digit:]]))
       bash /home/presto-data.sh;;
    *)  echo "Unrecognized hostname $hostname" ;;
esac

或者

#!/usr/bin/env bash
hostname=$(hostname -s)

shopt -s extglob

case $hostname in
    presto+([[:digit:]])-*
       bash /home/presto.sh;;
    presto-data+([[:digit:]])-*
        bash /home/presto-data.sh;;
    *)  echo "Unrecognized hostname $hostname" ;;
esac

这个方法通过 *- 分割前缀和后缀,同时通过 ? 精确指定了尾部字符串 -xx 的格式,使其具有更强的限定。

步骤:

  1. 保存修改后的脚本。
  2. 给脚本添加执行权限:chmod +x /tmp/script.sh
  3. 执行脚本: /tmp/script.sh

请注意,该方法可能并不总是必要,使用 * 进行匹配对于许多场景都足够。但是, 如果对匹配有更严格要求时,使用限定符 ? 或结合 [[:digit:]] 将带来更加准确的控制。

安全建议

  1. 仔细测试匹配规则 : 在生产环境中使用匹配之前,应该在测试环境中充分验证。 这能够避免不符合预期的执行和脚本运行错误。
  2. 考虑更强大的主机名匹配方法 :对于更复杂的主机名模式, 可能需要考虑使用更灵活的正则表达式或主机名匹配的工具, 避免 Bash 脚本因为规则复杂带来不可预测的错误。
  3. 减少匹配范围 :尽量使用具体的前缀进行匹配,而不是过多的使用 *, 以减小误匹配的可能,特别是 case 分支数量增多的情况下。
  4. 捕获并记录异常 : 如果无法匹配, 可以进行记录,以便问题排查, 提升系统的健壮性。
  5. 不要盲目假设主机名的格式 : 系统环境的变化可能导致主机名格式改变。脚本应考虑这种可能性,保证足够的鲁棒性。

总而言之, 使用通配符 * 是解决主机名部分匹配最有效也最易用的办法,同时如果考虑对匹配规则更加具体地控制,则使用 ? 进行更严格的限定也会很有帮助。合理运用它们, 可使 case 语句具有更大的灵活性和准确性。