bash 读行循环在第一行之后停止时的 Shell 脚本

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13800225/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 23:05:29  来源:igfitidea点击:

Shell script while read line loop stops after the first line

bashshellsshwhile-loop

提问by bcbishop

I have the following shell script. The purpose is to loop thru each line of the target file (whose path is the input parameter to the script) and do work against each line. Now, it seems only work with the very first line in the target file and stops after that line got processed. Is there anything wrong with my script?

我有以下 shell 脚本。目的是遍历目标文件的每一行(其路径是脚本的输入参数)并对每一行进行处理。现在,它似乎只适用于目标文件中的第一行,并在该行得到处理后停止。我的脚本有问题吗?

#!/bin/bash
# SCRIPT: do.sh
# PURPOSE: loop thru the targets 

FILENAME=
count=0

echo "proceed with $FILENAME"

while read LINE; do
   let count++
   echo "$count $LINE"
   sh ./do_work.sh $LINE
done < $FILENAME

echo "\ntotal $count targets"

In do_work.sh, I run a couple of sshcommands.

在 中do_work.sh,我运行了几个ssh命令。

回答by dogbane

The problem is that do_work.shruns sshcommands and by default sshreads from stdin which is your input file. As a result, you only see the first line processed, because sshconsumes the rest of the file and your while loop terminates.

问题是do_work.sh运行ssh命令并默认ssh从作为输入文件的 stdin 读取。结果,您只能看到处理的第一行,因为ssh消耗了文件的其余部分并且您的 while 循环终止。

To prevent this, pass the -noption to your sshcommand to make it read from /dev/nullinstead of stdin.

为防止出现这种情况,请将-n选项传递给您的ssh命令以使其读取/dev/null而不是标准输入。

回答by tripleee

More generally, a workaround which isn't specific to sshis to redirect standard input for any command which might otherwise consume the whileloop's input.

更一般地说,一种非特定的解决方法是ssh重定向任何可能消耗while循环输入的命令的标准输入。

while read -r LINE; do
   let count++
   echo "$count $LINE"
   sh ./do_work.sh "$LINE" </dev/null
done < "$FILENAME"

The addition of </dev/nullis the crucial point here (though the corrected quoting is also somewhat important; see also When to wrap quotes around a shell variable?). You will want to use read -runless you specifically require the legacy slightly odd behavior you get without -r.

的添加</dev/null是这里的关键点(尽管更正的引用也有些重要;另请参阅何时将引号括在 shell 变量周围?)。您将要使用的read -r,除非你特别要求传统有点奇怪的行为,你没有-r

Another workaround of sorts which is somewhat specific to sshis to make sure any sshcommand has its standard input tied up, e.g. by changing

另一种有点特定的解决方法ssh是确保任何ssh命令都绑定了其标准输入,例如通过更改

ssh otherhost some commands here

to instead read the commands from a here document, which conveniently (for this particular scenario) ties up the standard input of sshfor the commands:

改为从 here 文档中读取命令,该文档方便地(对于此特定场景)绑定了ssh命令的标准输入:

ssh otherhost <<'____HERE'
    some commands here
____HERE

回答by jacobm654321

ssh -n option prevents checking the exit status of ssh when using HEREdoc while piping output to another program. So use of /dev/null as stdin is preferred.

ssh -n 选项可防止在将输出通过管道传输到另一个程序时使用 HEREdoc 时检查 ssh 的退出状态。所以使用 /dev/null 作为标准输入是首选。

#!/bin/bash
while read ONELINE ; do
   ssh ubuntu@host_xyz </dev/null <<EOF 2>&1 | filter_pgm 
   echo "Hi, $ONELINE. You come here often?"
   process_response_pgm 
EOF
   if [ ${PIPESTATUS[0]} -ne 0 ] ; then
      echo "aborting loop"
      exit ${PIPESTATUS[0]}
   fi
done << input_list.txt