我想测试从文件中读取的一行是否具有特定的开头和结尾,其中包含变量中保存的单词。这是一些代码:
输入文件是:
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 中语法可能略有不同,但原理是相同的。)