2013-09-11 4 views
3

Конечная цель состоит в том, чтобы мой скрипт bash выполнял команду на нескольких серверах. Я почти это настроил. Моя аутентификация SSH работает, но этот простой цикл while убивает меня. Когда я исполняю время цикла, читая мой файл для имен хостов, он отлично работает, когда я запускаюwhile loop to read file заканчивается преждевременно

SSH $ HOST «uname -a»

но при попытке выполнить другую команду SSH ,

SSH $ HOST "oslevel -s"

цикл, а заканчивается рано! Я не могу понять. Зачем нужно, чтобы цикл 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"] в то время цикла?

+2

возможно дубликат [SSH в Bash Script портя File Read] (http://stackoverflow.com/questions/6585100/ssh-in-bash-script-messing-up-file-read) –

+0

@ Игнасио Васкес-Абрамс. Кроме того, есть еще одно решение. Кроме того, если пользователь каким-то образом хочет взаимодействовать с 'ssh', который не может быть использован. – konsolebox

+0

@konsolebox Это, возможно, причина для написания лучшего ответа на этот другой вопрос, а не для разделения фокуса. (Да, я отвечаю здесь, но я тоже * голосую, чтобы закрыть). –

ответ

0

В решении указано here Используйте -n вариант для ssh или открыть файл с другой ручкой:

while read -u 4 HOST 
    do 
    echo $HOST 
    ssh $HOST "uname -a" 
    ssh $HOST "oslevel -s" 
    echo "" 
    done 4< hosts.list` 
5

При запуске команды, которые читают из стандартного ввода (например, ssh) внутри цикла, вы должны убедиться, что либо:

  • Ваш цикл не итерация стандартного ввода
  • Ваша команда была его STDIN перенаправлены:

... в противном случае команда может потреблять вход, предназначенный для цикла, заставляя его закончить.

Бывший:

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

... который, используя Баш 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 
+2

(Чтобы узнать больше об автоматическом назначении дескриптора файла, см. Второй абзац в разделе «REDIRECTION» в справочной странице bash.) – kojiro

-1

возможно с питоном 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 "++++++++++++++++++++++++++" 
+1

Кстати - если вы читали список из 'sys.stdin', как это делает сценарий оболочки родителя, ваш Программа Python имела бы ту же самую проблему. Поэтому он не переписывается в Python как таковой, который исправляет проблему, он выделяет отдельный fd, а не повторно использует stdin (который 'open()' делает из коробки). –

+0

:/i запустил этот скрипт wiyh без ошибок, а также список хостов с 10 хостами – Dat30

+2

Правильно, это сработает - но это не так, потому что это Python, он работает, потому что он не использует повторно FD 0 для открытый вызов. –

1

Назначить массив перед циклом, чтобы вы не использовали stdin для своих переменных цикла. ssh внутри цикла может затем использовать stdin, не мешая вашему циклу.

readarray a < hosts.list 
for HOST in "${a[@]}"; do 
     ssh $HOST "uname -a" 
     #...other stuff in loop 
done 
Смежные вопросы