остановка процесса ssh, который отправляется в фоновый режим, без повреждения стандартного вывода
Мой сценарий направлен на извлечение текстового файла журнала, используяtail -f
и трассировка Wireshark с использованием . Но я не знаю, являются ли это лучшими вариантами для моей цели.
Мой сценарий должен быть отправлен на машину (которую я называю сервером), а затем с этой машины на другую (называемую блейдом), поэтому я создал эти две функции для оптимизации отправки команд:
processIDs=()
# sends command $2 to server $1, piping output to file $3 on local machine
server_cmd() {
ssh -i /home/$USER/.ssh/id_rsa root@$1 $2 1>>$3 2>>$errorOutput &
processIDs+=($!)
}
# sends command $3 to blade $2 of server $1, piping output to file $4 on local machine
blade_cmd() {
server_cmd $1 "ssh root@$2 \"$3\"" $4
}
Идентификаторы процессов сохраняются в массиве каждый раз, когда я отправляю вызов в фоновый режим.
В моем сценарии я делаю переменное количество вызовов (в зависимости от выбора пользователя) кblade_cmd
функция:
blade_cmd $server_ip $server_blade_ip "tail -f \\\$(ls -1tr ${path}_Debug_* | tail -1)" debug.log
blade_cmd $server_ip $server_blade_ip "tail -f \\\$(ls -1tr ${path}_Report_* | tail -1)" report.log
blade_cmd $server_ip $server_blade_ip "tshark -i eth7 -w -" tshark.pcap
Затем выполните действия, которые генерируют журналы/трассировки, а затем завершите процессы следующим образом:
# kill all generated processes on the array
for i in ${!processIDs[@]}; do
kill ${processIDs[i]}
wait ${processIDs[i]} 2>>$errorOutput
done
Но при такой настройке процессы на удаленных машинах не уничтожаются и остаются зависающими.
Решение, которое я нашел для уничтожения процессов, - это вызватьssh
с-tt
флаг, чтобы заставитьtty
что устраняет проблему нераспространения уничтожения, исходящего с локального компьютера, но затем получаемые мной журналы/трассировки повреждаются баннером входа в систему и различными символами новой строки, которые отображают журналы и особенноtshark
следы бесполезны.
Мне нужны некоторые рекомендации о том, как двигаться дальше.
1 ответ
В моих тестах пультtshark -w - …
автоматически завершает работу при выходе локального устройства, даже если я создаю цепочку, как вы; по крайней мере, когда пытается продолжать писать. Я думаю, что это механизм, описанный здесь: Почему не
tail -f … | grep -q …
выйти, когда найдет совпадение?
Обратите внимание, что первая запись после локальных выходов, вероятно, приведет к выходу только промежуточного (на сервере ), следующая запись приведет к выходу.
Это похоже на on Blade , за исключением того, что он может (а может и не быть) «умным» и обнаруживать сломанную трубу (см. Связанный ответ). Тем не менее, промежуточное звено не так уж и умно.
Так что да, в некоторых случаях «процессы на удаленных машинах […] остаются зависшими».
Есть хитрость, позволяющая сделать удаленный выход или выйти сразу после локального выхода. Вы не можете использовать этот трюк с удаленными командами, которые должны читать со стандартного ввода (т.е. в конечном итоге со стандартного ввода локального устройства), но поскольку иtail -f
не используйте их стандартный ввод, в этом случае трюк будет полезен. Это трюк:
На лезвии вместо запуска:
# shell code for blade
tshark … & cat >/dev/null; kill "$!"
Обратите внимание, что локально вам необходимо настроить цитирование так, чтобы оно было расширено на блейде , а не раньше. Для краткости я решил разместить команду в том виде, в котором должен получиться снаряд на клинке .
tshark …
теперь работает в фоновом режиме на Blade , однако это не должно мешать ему работать. в конечном итоге считывает из стандартного ввода локального устройства и будет оставаться там до тех пор, пока локальный ввод не завершится или его стандартный ввод не сломается или не будет исчерпан. Если локальный выход или его стандартный ввод прерываются или исчерпаны, он получит условие EOF и завершит работу. Потом убьет на лезвии .
Когдаtshark
, иkill
больше нет, оболочка на лезвии выходит и соответствующий экземплярsshd
при выходе блейда , поэтому и на сервере . Чисто.
Тот же трюк можно использовать, чтобы сделатьtail -f …
Выход.
Теперь нам нужно позаботиться о местной стороне.
Пульт будет читать то, что читает локальный. Без перенаправления локальный файл будет использовать стандартный ввод локального сценария (стандартный ввод может быть терминалом, обычным файлом или чем-то еще). В общем, вы можете не позволять локальному компьютеру использовать стандартный ввод сценария. Также, если условие EOF произойдет преждевременно, произойдет преждевременный выход; мы хотим, чтобы он завершал работу только после локального выхода, а не когда локальный стандартный ввод исчерпан. По этим причинам полезно подключить локальный стандартный ввод к чему-то другому, а не к стандартному вводу сценария. Не может быть/dev/null
потому что EOF произойдет немедленно. Это не должно быть/dev/zero
потому что он будет передавать ноль байтов напрасно. Возможноtail -f /dev/null
:
# locally inside your function
tail -f /dev/null | ssh … &
но потом$!
сообщит вам PID, и после убийства этого локального объекта останется, если только он не «умный» (опять же, см. Связанный ответ). Только если ваш локальный компьютер «умный», тогда это будет чистый способ, не оставляющий зависающих процессов.
В качестве альтернативы вы можете использовать фиктивный фифо. Предварительно следует открыть его для чтения и записи, чтобы ничего не зависало. Тем не менее, нет необходимости передавать что-либо через fifo. Пример:
# locally
mkfifo dummy
exec 3<>dummy
rm dummy
# then inside your function
<&3 ssh … &
Вы можете использовать один и тот же fifo для многих экземпляров . В этом примере я отвязал fifo от каталога сразу после открытия файлового дескриптора, поэтому дальнейшее обслуживание не требуется. Ядро действительно избавится от Fifo, когда оно больше не будет использоваться.
Так или иначе (т.е. с "умными"tail
или фифо) теперь достаточно убитьssh
локально и удаленноcat
на блейде увидит EOF и выйдет, а на блейде и сервере все произойдет, как описано выше.