如何在Bash中通过变量传递含通配符的子串进行搜索?
Bash 通配符子串匹配的变量传递方案
Bash支持带通配符的子串检查,比如使用*作为通配符时,下面的写法可以正常工作:
# 可正常运行 line="foo bar baz" if [[ $line == *"foo "*" baz"* ]]; then echo "found" fi
问题1:如何通过变量传递包含通配符的搜索字符串?
直接将带通配符的内容存入变量后匹配会失败,因为变量中的通配符会被当作普通字符处理:
# 执行失败 line="foo bar baz" search='foo "*" baz' echo "$search" if [[ $line == *"$search"* ]]; then echo "found" fi
问题2:如何处理$search,让脚本用户只需传入foo * baz即可实现匹配?
此前找到的方案受限于通配符数量,并非最优解:
line="foo bar baz" search="foo * baz" IFS=\* read -r search1 search2 search3 search4 <<< "$search" if [[ $line == *"$search1"*"$search2"*"$search3"*"$search4"* ]]; then echo "found" fi
可行解决方案
方案1:使用eval(注意安全风险)
若能确保search变量的输入可信,可通过eval将变量内容解析为匹配模式:
line="foo bar baz" search='foo * baz' if eval "[[ \$line == *\"$search\"* ]]"; then echo "found" fi
注意:
eval会执行变量中的任意命令,若search包含恶意内容会引发安全问题,仅适用于可控输入场景。
方案2:正则表达式匹配(推荐)
利用Bash的=~操作符做正则匹配,将用户输入的*替换为正则语法中的.*(匹配任意长度字符):
line="foo bar baz" search="foo * baz" # 将搜索字符串中的*替换为正则的.* regex=${search//\*/.*} if [[ $line =~ $regex ]]; then echo "found" fi
该方案无通配符数量限制,且安全性更高,用户只需传入foo * baz即可完成匹配。
方案3:开启扩展通配符
通过shopt -s extglob开启扩展通配符后,可直接将变量作为匹配模式使用:
shopt -s extglob line="foo bar baz" search='foo * baz' if [[ $line == $search ]]; then echo "found" fi
注意:开启扩展通配符后支持更多复杂匹配规则,但同样需注意输入内容的安全性。
内容的提问来源于stack exchange,提问作者mgutt
相关产品推荐
相关产品推荐

