#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 Это будет надежно работать только в том случае, если команда не включает никаких метасимволов оболочки (кавычки, экранирования, каналы, перенаправления и т.д.). Функции — действительно лучший способ сделать это.