2
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()是否在此处执行的侵入性最小的解决方案是什么?

4

5 回答 5

3

如果执行循环,您可以使用flag将更改其值的 a。下面是一个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如果跨度 a ,您需要使用以下内容sub-shell(感谢下面所有评论的人)

 while read line
   do
       fn=$(basename $line)
       do_something()
       flag="true"
   done < <(grep '^http://.*\.osm\..*$' list.txt)
于 2013-05-14T16:06:07.933 回答
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并对其进行后处理来避免,正如另一个答案中所建议的那样,但在某些方面这更容易理解......

于 2013-05-14T16:16:10.177 回答
2

将 的输出保存grep在变量中并显式测试它。

filtered=$(cat list.txt | grep ....)

if [ -z "$filtered" ] ;
  ... handle empty output ..
 else
  ... do your while loop here... 
fi

顺便说一句:换行符保留在 中"$filtered",但请务必在使用时引用它。

于 2013-05-14T16:16:45.737 回答
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
于 2013-05-14T16:21:18.043 回答
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

然后使用更适合您需要的一种。

于 2013-05-14T16:31:37.220 回答