在一个bash脚本中,我有一个我想要grep的文件中的行列表,然后在标准输出上显示,这是最简单的一次读取:
grep "regex" "filepath" | while read line; do
printf "$line\n"
done
但是,如果grep没有匹配行,我想通知用户。我知道可以通过updating a variable inside the loop来做到这一点,但似乎更优雅的方法(如果可能的话)是尝试在until循环中读取一行,如果没有输出,则会出现错误消息显示。
这是我的第一次尝试:
grep "regex" "filepath" | until [[ -z ${read line} ]]; do
if [[ -z $input ]]; then
printf "No matches found\n"
break
fi
printf "$line\n"
done
但在这种情况下,read命令格式不正确,我不确定查询这个短语的另一种方式。这种方法是否可行,如果没有,是否有更合适的解决方案?
答案 0 :(得分:20)
如果您只想在不匹配时显示消息,则根本不需要循环。相反,您可以使用grep的返回码。一个简单的if
语句就足够了:
if ! grep "regex" "filepath"; then
echo "no match" >&2
fi
这将显示grep匹配的结果(因为这是grep的默认行为),如果没有,则会显示错误消息。
if !
的常用替代方法是使用||
运算符。 foo || bar
可以理解为"执行foo
或执行bar
"或者#34;如果不是foo
则bar
"
grep "regex" "filepath" || echo "no match" >&2
答案 1 :(得分:1)
正如@jordanm所提到的,你提到的用例中不需要循环。
output=$(grep "regex" "file")
if [[ -n $output ]]; then
echo "$output"
else
echo "Sorry, no results..."
fi
如果您需要迭代结果进行处理(而不是仅显示到stdout),那么您可以执行以下操作:
output=$(grep "regex" "file")
if [[ -n $output ]]; then
while IFS= read -r line; do
# do something with $line
done <<< "$output"
else
echo "Sorry, no results..."
fi
此方法避免使用管道或子shell,以便在循环中进行的任何变量赋值都可用于脚本的其余部分。
此外,我不确定这是否与您尝试做的事情有关,但grep确实能够从文件加载模式(每行一个)。它被调用如下:
grep search_target -f pattern_file.txt
答案 2 :(得分:1)
John Kugelman的回答是正确而简洁的,你应该接受它。我正在解决有关语法的问题,只是为了完整性。
你不能使用${read line}
来执行read
- 括号语法实际上(含糊地)意味着你想要一个名字包含空格的变量的值。也许你正在为$(read line)
拍摄,但实际上,编写until
循环的正确方法更像是
grep "regex" "filepath" | until read line; [[ -z "$line" ]]; do
...但当然,当没有输出时,管道将不会收到任何行,因此while
和until
都是错误的。
值得强调的是,您需要单独do
的原因是您可以在其中拥有多个命令。甚至像
while output=$(grep "regex filepath"); echo "grep done, please wait ...";
count=$(echo "$output" | wc -l); [[ $count -gt 0 ]]
do ...
尽管如此,这比你真正需要的更加神秘。 (在这种特殊情况下,您可能希望实际上想要if
,而不是while
。)
正如其他人已经指出的那样,没有理由在这里使用类似的循环,但是我想要解决关于如何在你真正想要的时候编写这样的循环的问题。