1. Скрипт в Args

1. Скрипт в Args

Предположим, я хочу подключиться к машине 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

Если вы хотите запустить скрипт на удаленном хостеиполучить интерактивную оболочку, то у вас есть два варианта:

  1. Поместите весь скрипт в аргументы командной строки для ssh.
  2. Отправьте скрипт на удаленный хост (например: с помощью 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сразу:

  1. sudo
  2. apt-get
  3. update;
  4. bash
  5. -l
  6. -c
  7. "bash"

Конечно же, sudoаргумент -l(список) является взаимоисключающим с -c(класс входа).

Связанный контент