4

最终目标是让我的 bash 脚本在多个服务器上执行命令。我几乎已经设置好了。我的 SSH 身份验证正在工作,但是这个简单的 while 循环让我很生气。当我执行 while 循环,读取我的文件以获取主机名时,当我运行

ssh $HOST "uname -a"

但是当我尝试运行另一个 ssh 命令时,

ssh $HOST "oslevel -s"

while 循环提前结束!我想不通。 为什么 while read do 循环在第一个命令中运行得非常好,但在添加第二个命令时却不行?

我有一个名为 hosts.list 的简单文本文件,它有 4 个主机名,每行一个。

    $ cat hosts.list
    pcced1bip04
    pcced1bit04
    pcced1bo02
    pcced1bo04

    $ cat getinfo.bash
    #!/bin/bash
    set -x
    while read HOST
      do
        echo $HOST
        ssh $HOST "uname -a"
        #ssh $HOST "oslevel -s"
        echo ""
      done  < hosts.list`

当它运行时,它工作正常。它逐行遍历文件并获取"uname -a". 所以一切都很好,对吧?(对不起,我打开了set -x)。

    $ ./getinfo.bash
    + read HOST
    + echo pcced1bip04
    pcced1bip04
    + ssh pcced1bip04 'uname -a'
    AIX pcced1bip04 1 6 0001431BD400
    + echo ''

    + read HOST
    + echo pcced1bit04
    pcced1bit04
    + ssh pcced1bit04 'uname -a'
    AIX pcced1bit04 1 6 0001431BD400
    + echo ''

    + read HOST
    + echo pcced1bo02
    pcced1bo02
    + ssh pcced1bo02 'uname -a'
    AIX pcced1bo02 1 6 0009FE2AD400
    + echo ''

    + read HOST
    + echo pcced1bo04
    pcced1bo04
    + ssh pcced1bo04 'uname -a'
    AIX pcced1bo04 1 6 0009FE2AD400
    + echo ''

    + read HOST
    $

当我启用[ssh $HOST "oslevel -s"] 行时会出现问题。当我这样做时,脚本只读取文件的第一行,然后停止。 为什么不进入其他线路?

    $ ./getinfo.bash
    + read HOST
    + echo pcced1bip04
    pcced1bip04
    + ssh pcced1bip04 'uname -a'
    AIX pcced1bip04 1 6 0001431BD400
    + ssh pcced1bip04 'oslevel -s'
    6100-06-02-1044
    + echo ''

    + read HOST
    $

如果我的脚本有问题,为什么只使用[ssh $HOST "uname -a"]while 循环就可以正常工作?

4

4 回答 4

5

如果您在循环内运行从标准输入(例如ssh)读取的命令,则需要确保:

  • 您的循环没有迭代标准输入
  • 您的命令已重定向其标准输入:

...否则,该命令可能会消耗用于循环的输入,从而导致它结束。

前者:

while read -u 5 -r hostname; do
  ssh "$hostname" ...
done 5<file

...使用 bash 4.1 或更高版本,可以使用自动文件描述符分配重写,如下所示:

while read -u "$file_fd" -r hostname; do
  ssh "$hostname" ...
done {file_fd}<file

后者:

while read -r hostname; do
  ssh "$hostname" ... </dev/null
done <file

...也可以,对于 ssh 单独来说,也可以用-n参数来近似(也可以从 重定向标准输入/dev/null):

while read -r hostname; do
  ssh -n "$hostname"
done <file
于 2013-09-12T00:23:56.227 回答
2

在循环之前分配给一个数组,这样您就不会对循环变量使用标准输入。然后ssh循环内部可以使用标准输入而不会干扰您的循环。

readarray a <  hosts.list
for HOST in "${a[@]}"; do 
       ssh $HOST "uname -a"
       #...other stuff in loop
done
于 2015-09-12T19:51:08.210 回答
0

作为此处指定的解决方案,使用-n选项ssh或打开具有不同句柄的文件:

while read -u 4 HOST
  do
    echo $HOST
    ssh $HOST "uname -a"
    ssh $HOST "oslevel -s"
    echo ""
  done 4< hosts.list`
于 2013-09-12T00:23:15.370 回答
-1

也许与 python XD

#!/usr/bin/python

import sys
import Queue
from subprocess import call

logfile = sys.argv[1]
q = Queue.Queue()

with open(logfile) as data:
    datalines = (line.rstrip('\r\n') for line in data)
    for line in datalines:
        q.put(line)


while not q.empty() :
    host = q.get()
    print "++++++ " + host + " ++++++"
    call(["ssh", host, "uname -a"])
    call(["ssh", host, "oslevel -s"])
    print "++++++++++++++++++++++++++"
于 2013-09-12T03:41:40.997 回答