while循环读取文件过早结束

时间:2013-09-11 23:58:10

标签: bash ssh while-loop

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

时工作正常
  

ssh $ HOST“uname -a”

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

  

ssh $ HOST“oslevel -s”

while循环提前结束!我无法弄清楚。 为什么while读取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
    $

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

4 个答案:

答案 0 :(得分:5)

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

  • 你的循环不是通过stdin迭代
  • 您的命令已重定向stdin:

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

前者:

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重定向stdin)来近似:

while read -r hostname; do
  ssh -n "$hostname"
done <file

答案 1 :(得分:1)

在循环之前分配给数组,这样就不会将stdin用于循环变量。然后循环中的ssh可以使用stdin而不会干扰你的循环。

readarray a <  hosts.list
for HOST in "${a[@]}"; do 
       ssh $HOST "uname -a"
       #...other stuff in loop
done

答案 2 :(得分:0)

正如指定的解决方案here使用-n的{​​{1}}选项或使用不同句柄打开文件:

ssh

答案 3 :(得分:-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 "++++++++++++++++++++++++++"