为何grep的*通配符在终端与bash脚本中表现不同
问题背景
需要检测指定Kubernetes Pod是否进入运行状态,实现逻辑为通过while循环持续拉取kubectl命令输出,从中匹配对应的状态字段判断结果。
现象观察
当前集群中运行着一个dummy测试Pod,执行kubectl get pods的输出如下:
kubectl get pods # dummy-7744bb4469-h2mrq 1/1 Running 0 58d
在*cli(命令行)*中直接执行如下命令时,可正常返回上述dummy Pod对应的行,匹配到的"dummy"字符串会彩色高亮显示:
kubectl get pods | grep dummy* # dummy-7744bb4469-h2mrq 1/1 Running 0 58d # 匹配到的"dummy"字段为彩色高亮状态
基于这个测试结果,在bash脚本中编写了如下while循环实现检测逻辑,其中位置参数$1传入的字符串为dummy:
function check_pod_running(){ while [ $(kubectl get pods | grep $1* | grep Running | wc -l) == 0]; ... } # $1传入参数为字符串dummy
但脚本执行时无法匹配到目标Pod的对应行,会持续卡在循环中直到超时。查阅grep通配符使用的相关资料后,将匹配规则从$1*改为$1.*后功能恢复正常,但仍存在疑问:为何同一条命令在cli中可正常运行,在执行相同逻辑的bash脚本中却失效?
未加引号的grep匹配模式,会先在当前工作目录执行shell文件名通配展开,完成展开后才会处理管道传入的输入。
出问题的脚本在执行grep逻辑前,提前执行了pushd命令切换工作目录,切换后的目录下恰好存在名称包含"dummy"的文件,导致$1*被通配展开为具体文件名(如dummy.txt),最终grep实际匹配的是该展开后的文件名字符串,自然无法从kubectl的输出中匹配到对应Pod行,因此匹配结果始终为空,循环无法正常退出。
额外语法提示:grep默认使用正则匹配规则,而非shell通配规则。正则语法中
*代表匹配前面的字符0次或多次,因此dummy*实际匹配的是dumm后接0个或多个y的字符串;如果要匹配dummy开头的任意内容,正确的正则写法应为dummy.*,这也是修改为$1.*后功能恢复正常的语法层面原因。
内容的提问来源于stack exchange,提问作者Hung

