Я хочу запустить несколько заданий на различных машинах с помощью ssh. Если пользователь затем прерывает основной сценарий, я хочу закрыть все задания корректно.
Вот короткий пример того, что я пытаюсь сделать:
#!/bin/bash
trap "aborted" SIGINT SIGTERM
aborted() {
kill -SIGTERM $bash2_pid
exit
}
ssh -t remote_machine /foo/bar.sh &
bash2_pid=$!
wait
Однако процесс bar.sh все еще выполняет удаленную машину. Если я делаю те же команды в окне терминала, оно закрывает процесс на удаленном хосте.
Существует ли простой способ заставить это произойти, когда я запускаю скрипт удара? Или я должен заставить его войти в систему удаленной машины, найти правильный процесс и уничтожить его тот путь?
править: Кажется, что я должен пойти с опцией B, уничтожив remotescript посредством другого соединения SSH
Таким образом, не я хочу знать, как я получаю remotepid? Я попробовал что-то вроде:
remote_pid=$(ssh remote_machine '{ /foo/bar.sh & } ; echo $!')
Это не работает, так как это блокируется.
Как я ожидаю переменной, чтобы распечатать и затем "выпустить" подпроцесс?
Определенно было бы предпочтительнее, чтобы ваша очистка управлялась ssh, который запускает процесс, а не приступать к уничтожению с помощью второго сеанса ssh позже.
Когда ssh подключен к вашему терминалу; ведет себя неплохо. Однако отсоедините его от своего терминала, и становится (как вы заметили) проблемой сигнализировать или управлять удаленными процессами. Вы можете закрыть ссылку, но не удаленные процессы.
Остается один вариант: использовать ссылку как способ для удаленного процесса получить уведомление о том, что ему необходимо завершить работу. Самый простой способ сделать это - использовать блокирующий ввод-вывод. Сделайте ввод удаленного чтения из ssh и когда вы хотите, чтобы процесс завершился; отправьте ему некоторые данные, чтобы удаленная операция чтения разблокировала и он мог продолжить очистку:
command & read; kill $!
Это то, что мы хотели бы запустить на удаленном компьютере. Мы вызываем нашу команду, которую хотим запустить удаленно; мы читаем строку текста (блоки до тех пор, пока не получим ее), и когда мы закончим, сигнализируем команде о завершении.
Чтобы отправить сигнал от нашего локального сценария на удаленный, все, что нам нужно сделать сейчас, это отправить ему строку текста. К сожалению, здесь Bash не предлагает много хороших вариантов. По крайней мере, если вы хотите быть совместимым с bash <4.0.
В bash 4 мы можем использовать сопроцессы:
coproc ssh user@host 'command & read; kill $!'
trap 'echo >&"${COPROC[1]}"' EXIT
...
Теперь, когда локальный сценарий завершается (не перехватывайте INT
, TERM
и т. Д.). Просто EXIT
) он отправляет новую строку в файл во втором элементе массива COPROC
. Этот файл представляет собой канал, который подключен к stdin
ssh
, эффективно маршрутизируя нашу линию на ssh
. Удаленная команда считывает строку, завершает чтение
и уничтожает
команду.
Перед bash 4 все стало немного сложнее, так как у нас нет сопроцессов. В этом случае нам нужно сделать конвейер самостоятельно:
mkfifo /tmp/mysshcommand
ssh user@host 'command & read; kill $!' < /tmp/mysshcommand &
trap 'echo > /tmp/mysshcommand; rm /tmp/mysshcommand' EXIT
Это должно работать практически в любой версии bash.
Вы можете рассмотреть возможность монтирования удаленной файловой системы и запуска сценария с главного блока. Например, если ваше ядро скомпилировано с fuse (можно проверить следующим образом):
/sbin/lsmod | grep -i fuse
Вы можете смонтировать удаленную файловую систему следующей командой:
sshfs user@remote_system: mount_point
Теперь просто запустите ваш скрипт на файле, расположенном в mount_point.