Изпълнете команда на отдалечени хостове чрез ssh от вътрешността на bash скрипт

Написах bash скрипт, който трябва да чете потребителски имена и IP адреси от файл и да изпълнява команда върху тях чрез ssh.

Това е hosts.txt:

user1 192.168.56.232
user2 192.168.56.233

Това е myScript.sh:

cmd="ls -l"

while read line
do
   set $line
   echo "HOST:" $1@$2
   ssh $1@$2 $cmd
   exitStatus=$?
   echo "Exit Status: " $exitStatus
done < hosts.txt

Проблемът е, че изпълнението изглежда спира, след като първият хост е готов. Това е резултатът:

$ ./myScript.sh
HOST: [email protected]
total 2748
drwxr-xr-x 2 user1 user1    4096 2011-11-15 20:01 Desktop
drwxr-xr-x 2 user1 user1    4096 2011-11-10 20:37 Documents
...
drwxr-xr-x 2 user1 user1    4096 2011-11-10 20:37 Videos
Exit Status:  0
$

Защо се държи така и как мога да го поправя?


person kavakli    schedule 04.12.2011    source източник


Отговори (4)


Във вашия скрипт задачата ssh получава същия stdin като read line и във вашия случай се случва да изяде всички редове при първото извикване. Така че read line може да види само първия ред на входа.

Решение: Затворете stdin за ssh или по-добре пренасочете от /dev/null. (Някои програми не харесват затварянето на stdin)

while read line
do
    ssh server somecommand </dev/null    # Redirect stdin from /dev/null
                                         # for ssh command
                                         # (Does not affect the other commands)
    printf '%s\n' "$line"
done < hosts.txt

Ако не искате да пренасочвате от /dev/null за всяка отделна задача в цикъла, можете също да опитате едно от следните:

while read line
do
  {
    commands...
  } </dev/null                           # Redirect stdin from /dev/null for all
                                         # commands inside the braces
done < hosts.txt


# In the following, let's not override the original stdin. Open hosts.txt on fd3
# instead

while read line <&3   # execute read command with fd0 (stdin) backed up from fd3
do
    commands...       # inside, you still have the original stdin
                      # (maybe the terminal) from outside, which can be practical.

done 3< hosts.txt     # make hosts.txt available as fd3 for all commands in the
                      # loop (so fd0 (stdin) will be unaffected)


# totally safe way: close fd3 for all inner commands at once

while read line <&3
do
  {
    commands...
  } 3<&-
done 3< hosts.txt
person Jo So    schedule 04.12.2011

Проблемът, който имате, е, че SSH процесът консумира целия stdin, така че read не вижда нищо от входа, след като първата ssh команда е изпълнена. Можете да използвате флага -n за SSH, за да предотвратите това да се случи, или можете да пренасочите /dev/null към stdin на командата ssh.

Вижте следното за повече информация: http://mywiki.wooledge.org/BashFAQ/089

person jordanm    schedule 04.12.2011

Уверете се, че командата ssh не чете от hosts.txt с помощта на ssh -n

person wnrph    schedule 04.12.2011
comment
Това не е така. Той просто използва променливите от цикъла while: ssh $1@$2 $cmd - person kavakli; 04.12.2011
comment
след това опитайте echo|ssh $1@$2 $cmd вместо това - person wnrph; 04.12.2011
comment
@kavakli ... и виж какво ще стане - person wnrph; 04.12.2011

Имам чувството, че въпросът ви е ненужно многословен..

По същество трябва да можете да възпроизведете проблема с:

while read line
do
   echo $line
done < hosts.txt

Което трябва да работи добре.. Редактирате ли правилния файл? Има ли специални знаци в него? Проверете го с подходящ редактор (например: vim).

person Karoly Horvath    schedule 04.12.2011
comment
Той вероятно няма да може да възпроизведе проблема с това, тъй като ехото не чете stdin. - person jordanm; 04.12.2011