使用正则表达式和变量进行 AND 条件运算

使用正则表达式和变量进行 AND 条件运算

我想测试从文件中读取的一行是否具有特定的开头和结尾,其中包含变量中保存的单词。这是一些代码:

输入文件是:

line one
#; line two
#; line three blah
line four

失败的最小脚本是:

declare ENDOFLINE= "blah"
exec 3< "inputfile"

while read LINE <&3
do
    if [[ ("$LINE" =~ "^#;") && (( ("$LINE" =~ "${ENDOFLINE%$}") )) ]]; 
    then
    echo score!
    else echo no score
    fi
done

但是,如果我这样做:

if [[ ("$LINE" =~ "^#;") && (( ("$LINE" =~ "blah$") )) ]];

它成功地识别了正确的行(=> #; 第三行等等)。换句话说,我需要一个复合测试条件,其中第一个测试是行的开头是否为“#;”行尾是变量 $ENDOFLINE 中包含的字符串。

谢谢你的帮助。

答案1

看起来像一个简单的错误:在 的 末尾${ENDOFLINE%$}删除 a ,但您想要做的是按字面意思使用,并在其后面加上 a 来指示行的结尾。$$ENDOFLINE$ENDOFLINE$

if [[ ("$LINE" =~ "^#;") && (( ("$LINE" =~ "${ENDOFLINE}$") )) ]];

这在 zsh 中有效,但在 ksh 或 bash 中无效。 Bash 要求正则表达式$不加引号(否则,它会按字面解释),而 ksh 不喜欢里面有双括号[[ … ]](它将它们解释为算术指令)。这个更简单的代码行适用于所有三个 shell(请注意,这[[…]]是少数不需要"…"变量扩展的地方之一):

if [[ $LINE =~ ^"#;" && $LINE =~ $ENDOFLINE$ ]];

如果$ENDOFLINE从不与重叠#;(例如,如果ENDOFLINE;foo,您将接受#;;foo但拒绝#;foo),您可以将其减少为单个测试:

if [[ $LINE =~ ^"#;".*$ENDOFLINE$ ]];

您还可以在此处使用通配符模式而不是正则表达式:

if [[ $LINE = "#;"*"$ENDOFLINE" ]];

[[…]]构造并不存在于所有 shell 中,它特定于 bash、ksh 和 zsh。在其他 shell(Bourne、dash、任何 POSIX)上,您可以使用以下结构进行通配符匹配case

case $LINE in
  "#;"*"$ENDOFLINE") echo score;;
  *) echo no score;;
esac

答案2

您还可以使用 grep 执行此操作:

end=blah
while read line; do
    if grep -Eq "^#;.*$end$" <<< "$line"; then
        echo score!
    else
        echo no score
    fi
done

(这是在 bash 中;在其他 shell 中语法可能略有不同,但原理是相同的。)

相关内容