有人可以解释一下这在 shell 脚本中意味着什么吗?
while read -r line
do
if [ "${line#*'Caused By'}" != "$line" ]; then
echo "Yes"
fi
done
答案1
${line#*'Caused By'}
是变量替换的一个特定实例${parameter#word}
(正如bash
手册中所写的,而且在 POSIX 标准中对于sh
外壳)。
在 中${parameter#word}
,模式word
将从 的值的开头删除$parameter
。它被称为“删除最小前缀模式”,因为它将删除最短word
与 (中的模式匹配的匹配前缀字符串##
代替#
它会删除最长匹配前缀字符串)。
在这个特定的示例中,字符串Caused by
(以及它之前的任何内容,感谢*
),如果存在,将从 的值中删除$line
。字符串周围的单引号是多余的。
通过将替换结果与变量本身的值进行比较,测试确定 的值是否$line
包含文本Caused by
,Yes
如果包含则打印。
这与以下效果相同
if [[ "$line" == *'Caused by'* ]]; then
echo 'Yes'
fi
在bash
,ksh93
或zsh
, 或
case "$line" in
*'Caused by'*) echo 'Yes'
esac
在任何sh
外壳中。
问题中的循环从标准输入读取“行”。参见问题“理解“IFS=读取-r行” ”对此进行讨论。
答案2
if 条件的左侧使用模式匹配bash 的功能。如果匹配的字符串包含“Caused By”,则该字符串将被删除。该行将不再与之前相同,因此不会触发 if 子句。
下面是一个可以在 shell 上运行的示例:
echo -e "Number 1 Caused by me.\nNumber 2 is normal.\n" |
while read line; do
echo "${line#*'Caused by'}"
done
结果:
me.
Number 2 is normal.
答案3
行动(或本例中的执行)总是更重要,所以让我们看看这个脚本在执行时会做什么(请原谅我冒昧地使输出更加详细):
while read -r line
do
if [ "${line#*'Caused by'}" != "$line" ]; then
echo "Line contains string Caused by"
else
echo "Line does not contain string Caused by"
fi
done
Input: String with Caused by
Output: Line contains string Caused by
Input: Just a normal string
Output: Line does not contain string Caused by
此脚本中使用的模式匹配是从开头到结尾"${line#*'Caused by'}
替换所有字符串(由于通配符)*
造成的在输入的行中,然后将其与原始$line
参数进行比较,看看它们是否相等。简单地说,它所做的只是检查该行是否包含该字符串造成的。最后打印出来行包含字符串 原因为如果该行确实包含造成的。
${parameter#word}
现在,通过一些示例简单介绍一下格式的 shell 参数扩展:
如果模式与参数值的开头匹配,则扩展的结果是具有最短匹配模式(“#”情况)或最长匹配模式(“##”情况)的参数扩展值)删除。
$ test=aabbcc
$ echo ${test#*bb}
$ cc
$ test=aabbcc
$ echo ${test#a*b}
$ bcc
最长匹配模式格式的示例:
$ test=aabbcc
$ echo ${test##a*b}
$ cc
参考: man bash
:${parameter#word}