bev*_*bev 3 bash ksh zsh regular-expression
我想测试从文件中读入的一行是否具有特定的开头和结尾,其中包含保存在变量中的单词。这是一些代码:
输入文件是:
line one
#; line two
#; line three blah
line four
Run Code Online (Sandbox Code Playgroud)
失败的最小脚本是:
declare ENDOFLINE= "blah"
exec 3< "inputfile"
while read LINE <&3
do
if [[ ("$LINE" =~ "^#;") && (( ("$LINE" =~ "${ENDOFLINE%$}") )) ]];
then
echo score!
else echo no score
fi
done
Run Code Online (Sandbox Code Playgroud)
但是,如果我这样做:
if [[ ("$LINE" =~ "^#;") && (( ("$LINE" =~ "blah$") )) ]];
Run Code Online (Sandbox Code Playgroud)
它成功识别了正确的行(=> #;第三行等等)。换句话说,我需要一个复合测试条件,其中第一个测试是行首是否为“#;” 该行的结尾是包含在变量 $ENDOFLINE 中的字符串。
谢谢你的帮助。
看起来像一个简单的错误:在 的末尾${ENDOFLINE%$}去掉 a ,但您想要做的是按字面意思使用并在它后面加上 a来表示行的结尾。$$ENDOFLINE$ENDOFLINE$
if [[ ("$LINE" =~ "^#;") && (( ("$LINE" =~ "${ENDOFLINE}$") )) ]];
Run Code Online (Sandbox Code Playgroud)
这在 zsh 中有效,但在 ksh 或 bash 中无效。Bash 要求 regexp$不加引号(否则,它会按字面解释),并且 ksh 不喜欢里面的双括号[[ … ]](它将它们解释为算术指令)。这条更简单的行适用于所有三个 shell(请注意,这[[…]]是您不需要"…"围绕变量扩展的少数几个地方之一):
if [[ $LINE =~ ^"#;" && $LINE =~ $ENDOFLINE$ ]];
Run Code Online (Sandbox Code Playgroud)
如果$ENDOFLINE从不与#;(例如,如果ENDOFLINE是;foo,您将接受#;;foo但拒绝#;foo),您可以将其简化为单个测试:
if [[ $LINE =~ ^"#;".*$ENDOFLINE$ ]];
Run Code Online (Sandbox Code Playgroud)
您还可以在此处使用通配符模式而不是正则表达式:
if [[ $LINE = "#;"*"$ENDOFLINE" ]];
Run Code Online (Sandbox Code Playgroud)
该[[…]]构造并不存在于所有 shell 中,它特定于 bash、ksh 和 zsh。在其他 shell(Bourne、dash、任何 POSIX)上,您可以使用以下case结构进行通配符匹配:
case $LINE in
"#;"*"$ENDOFLINE") echo score;;
*) echo no score;;
esac
Run Code Online (Sandbox Code Playgroud)