bash中while read仅执行一次且正则匹配失效的技术问题
解决Shell循环仅执行一次的正则匹配问题
问题场景
现有file.txt内容如下:
G9DG1.fqdn.com G9DG2.fqdn.com G9DG3.fqdn.com G9DG4.fqdn.com G9DC1.fqdn.com G9DC3.fqdn.com G9DG5.fqdn.com G9DC4.fqdn.com
尝试用以下while read脚本逐行检查主机名是否匹配正则G[0-9]{1,2}[DS]C[0-9]{1,3}.fqdn.com:
while read -r line do if [[ "$line" == "$(grep -E 'G[0-9]{1,2}[DS][C][0-9]{1,3}.fqdn.com')" ]] then echo "$line matches" else echo "$line doesn't match" fi done < file.txt
但脚本仅输出第一行结果就退出:
G9DG1.fqdn.com doesn't match
期望输出应该是逐行判断的结果:
G9DG1.fqdn.com doesn't match G9DG2.fqdn.com doesn't match G9DG3.fqdn.com doesn't match G9DG4.fqdn.com doesn't match G9DC1.fqdn.com matches G9DC3.fqdn.com matches G9DG5.fqdn.com doesn't match G9DC4.fqdn.com matches
问题原因
- 标准输入被耗尽:脚本中
grep命令未指定输入文件,默认读取标准输入(即file.txt)。第一次循环时,grep会读取整个file.txt内容,导致后续read命令无剩余内容可读取,循环直接终止。 - 匹配逻辑错误:用
==将单行的$line与grep输出的多行结果做比较,逻辑不成立,无法正确判断单行是否匹配正则。
解决方案
方法1:使用Bash内置正则匹配
直接用Bash的[[ $line =~ 正则表达式 ]]语法,无需调用外部grep命令,避免标准输入冲突:
while read -r line do if [[ "$line" =~ ^G[0-9]{1,2}[DS]C[0-9]{1,3}\.fqdn\.com$ ]] then echo "$line matches" else echo "$line doesn't match" fi done < file.txt
注意:正则中的
.需转义为\.,否则会匹配任意字符;加上^和$确保整行完全匹配,避免部分匹配。
方法2:让grep读取指定内容而非标准输入
如果坚持用grep,可以通过管道将当前行传给grep,并用-q参数静默判断(更高效):
while read -r line do if echo "$line" | grep -qE '^G[0-9]{1,2}[DS]C[0-9]{1,3}\.fqdn\.com$' then echo "$line matches" else echo "$line doesn't match" fi done < file.txt
-q参数让grep仅返回退出状态码,不输出内容,适合条件判断场景。
验证结果
执行上述任一修正后的脚本,都会输出期望的逐行判断结果。
内容的提问来源于stack exchange,提问作者Saeed
相关产品推荐
相关产品推荐

