
Предположим, я хочу подключиться к машине B через машину A. Как я узнал, есть несколько способов сделать это, например:
ssh -T -J user@machineA user@machineB << END_OF_SSH_CONNECTION
# Some commands in machine B
END_OF_SSH_CONNECTION
или
ssh -T user@machineA << END_OF_MACHINE_A
ssh -T machine B << END_OF_MACHINE_B
# Some commands in machine B
END_OF_MACHINE_B
END_OF_MACHINE_A
Однако мне не ясно, как запустить интерактивную оболочку, в которой пользователь может вводить команды при подключении к машине B. Например, это работает:
ssh user@machineA -t 'bash -l -c "bash"'
и это тоже работает:
ssh -J user@machineA user@machineB -t 'bash -l -c "bash"'
Однако следующее не работает:
ssh -J user@machineA user@machineB -t 'sudo apt-get update; bash -l -c "bash"'
E: Command line option 'l' [from -l] is not understood in combination with the other options.
Connection to machineB closed.
И ни следующее:
ssh -J user@machineA user@machineB -t 'if [ 1 -eq 1 ]; then bash -l -c "bash"; fi'
/usr/local/sbin/start_ttylog.sh: line 67: exec: if: not found
Connection to machineB closed.
Я также попробовал это:
ssh -T -J user@machineA user@machineB << EOF
# Some commands on machineB
# Check whether apache2 has been correctly installed
if [ $(dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -c "ok installed") -eq 1 ];
then
printf "done\n";
else
printf "fail\nStarting an interactive shell: enter exit to quit\n";
bash -l -c "bash";
fi
EOF
Последняя версия почти работает (т.е. не возвращает ошибок), но она не запускает интерактивную оболочку, в которой пользователь может вводить команды, как я ожидал.
Надеюсь, кто-нибудь сможет мне помочь. Заранее спасибо.
решение1
Спасибо за помощь, @attie. Я немного изменил предложенный вами код, о чем сообщаю ниже.
#!/usr/bin/env bash ssh -T -J user@machineA user@machineB 'cat >/tmp/myscript' <<"EOF" if dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -q 'ok installed'; then echo "done"; else echo "fail, starting an interactive shell"; bash -l -c "bash"; fi EOF ssh -t -J user@machineA user@machineB "bash '/tmp/myscript'"
в это, для чего даже не нужно записывать во внешний файл.
#!/usr/bin/env bash
ssh -T -J user@machineA user@machineB << "EOF"
if dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -q "ok installed"; then
echo "done";
else
echo "fail, starting an interactive shell";
bash -l -c "bash";
fi
EOF
По сути, я пропустил кавычки EOF
, используемые для того, чтобы избежать попытки расширения поля ${Status}
.
решение2
Если вы хотите запустить скрипт на удаленном хостеиполучить интерактивную оболочку, то у вас есть два варианта:
- Поместите весь скрипт в аргументы командной строки для
ssh
. - Отправьте скрипт на удаленный хост (например: с помощью
scp
илиssh
), а затем выполните его (например: с помощьюssh
)
1. Скрипт в Args
Ваш последний пример находится на грани "длинный" для этого подхода, но вы можете улучшить читабельность, используяmapfile
(встроенный в bash
). Обратите внимание на кавычки "EOF"
, чтобы избежать попытки расширения ${Status}
.
mapfile -t SCRIPT <<"EOF"
if dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -q 'ok installed'; then
echo "done";
else
echo "fail, starting an interactive shell";
bash -l -c "bash";
fi
EOF
ssh -t -J user@machineA user@machineB "${SCRIPT[@]}"
2. Нажмите Скрипт, затем Запустите
Бонусные баллы за использование mktemp
и последующую уборку. Примечание процитировано "EOF"
еще раз.
На основании одного из предоставленных вами сообщений об ошибках (около exec
, подробнее см. ниже), такое использование, cat >/tmp/myscript
скорее всего, не сработает.
ssh -T -J user@machineA user@machineB 'cat >/tmp/myscript' <<"EOF"
if dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -q 'ok installed'; then
echo "done";
else
echo "fail, starting an interactive shell";
bash -l -c "bash";
fi
EOF
ssh -t -J user@machineA user@machineB "bash '/tmp/myscript'"
Первым шагом всегда должна быть попытка разбить проблему на простейшие формы... Что касается вашего последнего заклинания, попробуйте следующее:
ssh -T user@machineA << EOF
bash -l -c "bash";
EOF
Что происходит? Вы получаете приветственные сообщения от удаленного хоста, но затем сеанс немедленно и молча завершается без ошибок.
Изменение -T
(явнозапрещатьРаспределение PTY) для -t
(принудительное распределение PTY) дает подсказку в правильном направлении:
ssh -t user@machineA << EOF
bash -l -c "bash";
EOF
Pseudo-terminal will not be allocated because stdin is not a terminal.
Это указывает на то, что вы используете stdin
для предоставления скрипта, а затем также пытаетесь подключить его stdin
(канал, а не терминал) к удаленному PTY.
Давайте уберем этот stdin
фактор:
ssh -t user@machineA bash -l -c "bash"
И это работает!
По сути выне могусовместно использовать stdin как со скриптом, так и с терминалом.
Что касается других ошибок:
E: Command line option 'l' [from -l] is not understood in combination with the other options.
Опять же, разберите его, чтобы найти проблему. К сожалению, эти команды работают для меня, я подозреваю, потому что системы, к которым у меня есть доступ, используют sh -c "${ARGS}"
или похожие. Однако другая ошибка, которую вы указали, дает подсказку:
/usr/local/sbin/start_ttylog.sh: line 67: exec: if: not found
Похоже, что ваша система использует exec
для запуска команды, заданной в качестве аргументов, ssh
..., что означает, что оболочка не может обрабатывать такие вещи, как if
или , ;
как вы надеетесь, — поэтому if
в пути нет двоичного файла, и он завершается ошибкой.
Равным образом все аргументы приводятся sudo
сразу:
sudo
apt-get
update;
bash
-l
-c
"bash"
Конечно же, sudo
аргумент -l
(список) является взаимоисключающим с -c
(класс входа).