Команда SSH не запускается из скрипта bash, но она запускается из оболочки

#linux #bash #shell

#linux #bash #оболочка

Вопрос:

Команда ssh не запускается из скрипта bash, но она запускается из оболочки.

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

Вывод оболочки показывает следующее:

  • Удаленный компьютер запущен
  • Скрипт находится на localhost, а команда ssh — в функции с именем doit
  • Выполнение скрипта возвращает ошибку в строке 5 (строка с командой ssh): «Нет такого файла или каталога»
  • Скопируйте и вставьте команду ssh в оболочку, нажмите enter, она выполняется и достигает удаленного компьютера, который возвращает ошибку, потому что ключ не настроен (ожидается)

Вывод из оболочки:

 ~ $ nping -c 1 104.248.173.32

Starting Nping 0.7.01 ( https://nmap.org/nping ) at 2019-04-23 22:04 ICT
libnsock mksock_bind_addr(): Bind to 0.0.0.0:0 failed (IOD #1): Invalid argument (22)
SENT (0.0016s) Starting TCP Handshake > 104.248.173.32:80
RECV (0.0017s) Handshake with 104.248.173.32:80 completed

Max rtt: 0.177ms | Min rtt: 0.177ms | Avg rtt: 0.177ms
TCP connection attempts: 1 | Successful connections: 1 | Failed: 0 (0.00%)
Nping done: 1 IP address pinged in 0.00 seconds
~ $ cat /tmp/test.sh
#!/usr/bin/env bash

function doit() {
  RUN="/usr/bin/ssh -o BatchMode=yes -o ConnectTimeout=3 root@104.248.173.32 hostname"
  "$RUN"
  echo "RESULT: $?"
}

doit  
~ $ /tmp/test.sh
/tmp/test.sh: line 5: /usr/bin/ssh -o BatchMode=yes -o ConnectTimeout=3 root@104.248.173.32 hostname: No such file or directory
RESULT: 127
~ $ /usr/bin/ssh -o BatchMode=yes -o ConnectTimeout=3 root@104.248.173.32 hostname
Host key verification failed.
~ $ echo $?
255
  

Я ожидал, что команда ssh в скрипте попытается запустить hostname на удаленной машине, и на удаленной машине произойдет ошибка, потому что ключ не настроен.

На самом деле произошло то, что команда ssh в скрипте не выполнялась, потому что была ошибка «Нет такого файла или каталога».

Почему я вижу ошибку «Нет такого файла или каталога», когда команда ssh запускается из скрипта, даже если скрипт есть, ssh есть и удаленный компьютер есть?

Комментарии:

1. Потому что вы пытаетесь запустить программу с именем /usr/bin/ssh -o BatchMode... вместо /usr/bin/ssh с аргументами -o BatchMode... . Нужна ли вообще RUN переменная (я предполагаю, что этот фрагмент мог быть извлечен из более крупного скрипта, где он действительно полезен)?

2. В зависимости от того, к чему вы здесь подключаетесь, вы можете рассмотреть возможность удаления общедоступного IP…

3. @cfillion Я не понимаю, в чем разница, которую вы пытаетесь выделить, разве команда не выполняется таким же образом из переменной? Да, вы правы, она была извлечена из другого скрипта, и переменная будет использована позже для вывода команды

4. @cppPH Спасибо, это тестовый сервер, который будет удален позже

5. Смотрите BashFAQ # 50: я пытаюсь поместить команду в переменную, но сложные случаи всегда терпят неудачу! Краткое резюме: не помещайте команды в переменные, они предназначены для хранения данных, а не кода.

Ответ №1:

 /usr/bin/ssh -o BatchMode=yes -o ConnectTimeout=3 root@ipaddress hostname
  

и

 "/usr/bin/ssh -o BatchMode=yes -o ConnectTimeout=3 root@ipaddress hostname"
  

…не совпадают. Первая выполняет команду /usr/bin/ssh с указанными аргументами. Последний обрабатывает всю строку, включая аргументы, как имя команды.

Вы выполнили первое при запуске команды в командной строке. Однако doit функция выполняет последнее с "$RUN" помощью. Вы получаете «Нет такого файла или каталога», потому что, действительно, внутри файла с именем нет ssh -o BatchMode... (усеченный для краткости) /usr/bin .

Либо выполните команду напрямую, если это возможно, либо удалите кавычки:

 function doit1() {
  /usr/bin/ssh -o BatchMode=yes -o ConnectTimeout=3 root@ipaddress hostname
  echo "RESULT: $?"
}

function doit2() {
  # assuming there is some usefulness to using a variable in the actual script
  RUN="/usr/bin/ssh -o BatchMode=yes -o ConnectTimeout=3 root@ipaddress hostname"
  $RUN
  echo "RESULT: $?"
}
  

Комментарии:

1. Пожалуйста, не используйте и не рекомендуйте eval — это огромный магнит для ошибок.

2. Это имеет большой смысл, я был сбит с толку на несколько секунд, потому что я помещал команды в переменные раньше и у меня не было никаких проблем, и теперь я понимаю, что это потому, что в тех случаях у меня не было двойных кавычек вокруг переменной, поэтому команда не выполнялась в виде строки. Используя $RUN вместо «$ RUN», и я получаю ожидаемый результат. Спасибо

3. @vy218 Это будет надежно работать только в том случае, если команда не включает никаких метасимволов оболочки (кавычки, экранирования, каналы, перенаправления и т.д.). Функции — действительно лучший способ сделать это.