139

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

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

FILENAME=$1
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"

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

4

5 回答 5

227

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

这不仅适用于ssh,而且适用于任何读取标准输入的命令,包括mplayerffmpegHandBrakeCLI等。

为防止这种情况,请将-n选项传递给您的ssh命令以使其从/dev/null标准输入而不是标准输入中读取。其他命令具有类似的标志,或者您可以普遍使用< /dev/null.

于 2012-12-10T11:56:30.357 回答
23

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

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

添加</dev/null是这里的关键点(尽管更正的引用也有些重要;另请参见何时在 shell 变量周围加上引号?)。read -r除非您特别需要没有-r.

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

ssh otherhost some commands here

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

ssh otherhost <<'____HERE'
    some commands here
____HERE
于 2019-03-25T09:32:51.937 回答
16

一个非常简单且强大的解决方法是更改​​命令接收输入的文件描述符。read

这是通过两个修改来实现的: 的-u参数read和 的重定向运算符< $FILENAME

在 BASH 中,默认的文件描述符值(即-uin的值read)是:

  • 0 = 标准输入
  • 1 = 标准输出
  • 2 = 标准错误

所以只需选择一些其他未使用的文件描述符,就像9只是为了好玩。

因此,以下将是解决方法:

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

注意两个修改:

  1. read变成read -u 9
  2. < $FILENAME变成9< $FILENAME

作为最佳实践,我对while我在 BASH 中编写的所有循环都执行此操作。如果您使用 嵌套循环,请为每个循环使用read不同的文件描述符(9、8、7、...)。

于 2021-02-12T21:16:34.837 回答
5

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
于 2015-11-14T22:54:02.110 回答
4

这发生在我身上,因为我有set -e并且grep一个循环返回没有输出(这给出了一个非零错误代码)。

于 2018-01-31T11:03:22.050 回答