尝试让一个变量满足长度不定的文本字符串。字符串中重要的部分是前几个字符。
var1=hello
if [ $var1 == hello ]; then
echo success
fi
或者
var1=hello
if [ $var1 == h*o ]; then
echo success
fi
输出:成功
但由于我关心的是前 3 个字符左右,这听起来合乎逻辑,但却不起作用:
var1=hello
if [ $var1 == hel* ]; then
echo success
fi
输出:-bash:[:参数太多
由于我只关心前几个字符,因此我可以这样做:
var1=hello
if [ ${var1:0:3} == hel ]; then
echo success
fi
那样可行,但我正在寻找出现该错误的原因的解释以及可能的更好的书面解决方案。
答案1
当您使用类似这样的*
in时if
,它将进行文件名扩展。因此,在第一个实例中,h*o
可能与当前目录中的文件匹配,因此测试通过。
匹配hel*
到多个文件,因此命令的参数太多if
。
尝试使用if [[ $var1 == hel* ]]; then
双括号将测试变成正则表达式,并且*
通配符将按预期工作。
答案2
我有一个技巧,用于在不使用内置 bash 正则表达式的情况下破解正则表达式。示例为 #2。其工作原理是,如果 grep 不匹配任何内容,则不返回任何输出(因此不存在字符串)。因此有两个测试,-z 表示“空字符串”,-n 表示“有数据”。
if [ -n "`echo $var1 | grep -e 'h.*o'`" ] ; then
echo 'water found'
fi
答案3
使用双括号在右表达式中启用模式匹配
if [[ "$var1" == hel* ]]
或使用正则表达式比较运算符。
if [[ "$var1" =~ ^hel.* ]]
(模式匹配和正则表达式不一样)
答案4
[[
是 bash 特有的,使用起来grep
很慢,因为它需要先启动一个新进程。有一种更简单、更快速的解决方案,适用于每个 POSIX 兼容 shell:
var1=hello
case $var1 in
hel*) echo success
esac
更通用的语法是:
case $var in
<pattern1>) action1 ; action2 ; action3 ; ... ; actionN ;;
<pattern2>) action1 ; action2 ; action3 ; ... ; actionN ;;
<pattern3>) action1 ; action2 ; action3 ; ... ; actionN ;;
*) action1 ; action2 ; action2 ; ... ; actionN ;;
esac
第一个匹配的模式定义要执行的操作。如果您想要else
仅在没有模式匹配时运行的操作,请使用*
模式,因为该模式将始终匹配。您可以使用 终止一组操作;;
,如果下一条指令是,esac
则这些操作是可选的。您还可以使用换行符来分隔指令,因此以下语法也是有效的:
case $var in
<pattern>)
action1
action2
action3
:
actionN
;;
*)
action2
action3
:
actionN
esac
在模式中,您可以使用*
and ?
,以及|
表示“或”和[...]
,如[abcd]
(匹配这 4 个字母中的任一个) 或如[A-Z]
(匹配 A 到 Z 的所有字母,以及!
否定匹配。例如
for var in abc 123 3a b5 934 ""
do
case $var in
"" | *[!0-9]*) echo "\"$var\" is NOT an integer!" ;;
*) echo "\"$var\" is an integer."
esac
done
输出:
"abc" is NOT an integer!
"123" is an integer.
"3a" is NOT an integer!
"b5" is NOT an integer!
"934" is an integer.
"" is NOT an integer!