cat list.txt | grep '^http://.*\.osm\..*$' | while read line; do
fn=$(basename $line)
do_something()
done
# TODO: check if it did something
如果grep命令什么都不返回,它将不会进入循环,并且 do_something()将不会被执行。
我无法检查while循环之外的$ fn中的内容,请参阅Bash variable scope。
检查 do_something()是否在此处执行的最少侵入性解决方案是什么?
答案 0 :(得分:3)
如果执行循环,您可以使用其值将被更改的flag
。下面是一个poc。
shopt -s lastpipe # bash 4.2 or greater only
flag="false"
cat list.txt | grep '^http://.*\.osm\..*$' | while read line; do
fn=$(basename $line)
do_something()
flag="true"
done
if [ "$flag" = "true" ]
then
echo "loop was executed"
fi
如果while
跨越sub-shell
,则需要使用以下内容(感谢所有评论如下的人)
while read line
do
fn=$(basename $line)
do_something()
flag="true"
done < <(grep '^http://.*\.osm\..*$' list.txt)
答案 1 :(得分:3)
由于while
循环在子shell中运行,因此它无法将值传播回父shell。但是,仍然有办法做想要的事情。这是一个:
if grep -q '^http://.*\.osm\..*$' list.txt # loop will definitely run
then
while read line
do
# do something with line
done < <(grep '^http://.*\.osm\..*$' list.txt)
else # no matches, loop will not run
# do something else
fi
它有两次运行grep
的副作用,这可以通过保存grep
的输出并对其进行后处理来避免,如另一个答案所示,但在某些方面,这是一个有点简单了解......
答案 2 :(得分:2)
将grep
的输出保存在变量中并明确测试。
filtered=$(cat list.txt | grep ....)
if [ -z "$filtered" ] ;
... handle empty output ..
else
... do your while loop here...
fi
顺便说一句:新行保留在"$filtered"
内,但请务必在使用时引用它。
答案 3 :(得分:2)
您可以使用流程替换来代替管道,这将允许有用地设置标志:
flag=0
while read line; do
flag=1
fn=$(basename $line)
do_something()
done < <( grep '^http://.*\.osm\..*$' list.txt )
if [[ $flag == 1 ]]; then
...
fi
答案 4 :(得分:1)
@chepner解决方案的变体:
flag=0
while read line; do
grep -q '^http://.*\.osm\..*$' <<< $line && {
flag=1
fn=$(basename $line)
do_something()
}
done < list.text
if [[ $flag == 1 ]]; then
...
fi
然后使用一个更符合您需求的产品。