Выполнить команду на удаленных хостах через 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 получает тот же стандартный ввод, что и read line, и в вашем случае случается так, что при первом вызове он поглощает все строки. Таким образом, read line увидит только самую первую строку ввода.

Решение: закрыть стандартный ввод для ssh или лучше перенаправить с /dev/null. (Некоторым программам не нравится, когда стандартный ввод закрыт)

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 использует весь стандартный ввод, поэтому чтение не видит никаких входных данных после запуска первой команды ssh. Вы можете использовать флаг -n для SSH, чтобы предотвратить это, или вы можете перенаправить /dev/null на стандартный ввод команды 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
Скорее всего, он не сможет воспроизвести проблему с этим, так как echo не читает стандартный ввод. - person jordanm; 04.12.2011