Ваше предположение, что оно ssh
само возвращает статус 255, верно. ssh
Страница людей заявляет , что:
ssh завершает работу с состоянием выхода удаленной команды или с 255, если произошла ошибка.
Если бы вы просто запустились ssh pi@10.20.0.10 "pkill -f asdf"
, вы, скорее всего, получили бы статус выхода 1
, соответствующий pkill
статусу « Нет соответствующих процессов ».
Задача состоит в том, чтобы понять, почему при запуске SSH возникает ошибка
ssh pi@10.20.0.10 "pkill -f asdf || true"
SSH удаленные команды
Сервер SSH запускает оболочку для запуска удаленных команд. Вот пример этого в действии:
$ ssh server "ps -elf | tail -5"
4 S root 35323 1024 12 80 0 - 43170 poll_s 12:01 ? 00:00:00 sshd: anthony [priv]
5 S anthony 35329 35323 0 80 0 - 43170 poll_s 12:01 ? 00:00:00 sshd: anthony@notty
0 S anthony 35330 35329 0 80 0 - 28283 do_wai 12:01 ? 00:00:00 bash -c ps -elf | tail -5
0 R anthony 35341 35330 0 80 0 - 40340 - 12:01 ? 00:00:00 ps -elf
0 S anthony 35342 35330 0 80 0 - 26985 pipe_w 12:01 ? 00:00:00 tail -5
Обратите внимание, что оболочкой по умолчанию является bash
и что удаленная команда - это не простая команда, а конвейер , «последовательность из одной или нескольких команд, разделенных оператором управления |
».
Оболочка Bash достаточно умна, чтобы понять, что если команда, передаваемая ей с помощью -c
опции, является простой командой , она может оптимизироваться, фактически не разветвляя новый процесс, т. Е. Она напрямую exec
выполняет простую команду вместо выполнения дополнительного шага. из fork
ING до того , как exec
с. Вот пример того, что происходит, когда вы запускаете простую удаленную команду ( ps -elf
в данном случае):
$ ssh server "ps -elf" | tail -5
1 S root 34740 2 0 80 0 - 0 worker 11:49 ? 00:00:00 [kworker/0:1]
1 S root 34762 2 0 80 0 - 0 worker 11:50 ? 00:00:00 [kworker/0:3]
4 S root 34824 1024 31 80 0 - 43170 poll_s 11:51 ? 00:00:00 sshd: anthony [priv]
5 S anthony 34829 34824 0 80 0 - 43170 poll_s 11:51 ? 00:00:00 sshd: anthony@notty
0 R anthony 34830 34829 0 80 0 - 40340 - 11:51 ? 00:00:00 ps -elf
Я сталкивался с таким поведением раньше, но я не мог найти лучшую ссылку, кроме этого ответа AskUbuntu .
поведение pkill
Так как pkill -f asdf || true
это не простая команда (это список команд ), выше оптимизации не могут произойти так , при запуске ssh pi@10.20.0.10 "pkill -f asdf || true"
, в sshd
процессе вилки и Execs bash -c "pkill -f asdf || true"
.
Как указывает ответ ctx, pkill
не будет убивать свой собственный процесс. Тем не менее, он будет убивать любой другой процесс , командная строка которого соответствует -f
шаблону. Команда bash -c
соответствует этому шаблону, поэтому убивает этот процесс - своего родителя (как это происходит).
Затем SSH-сервер видит, что процесс оболочки, который он запустил для запуска удаленных команд, был неожиданно завершен, поэтому он сообщает об ошибке клиенту SSH.
pkill
убивает его процесс оболочки родительского , потому что его агд список совпадает с регулярным выражением, я подниму терминологическую возражение:x || y
это не команда соединения , это список команд .x||y
как список команд. Теперь я отредактировал свой ответ, включив ссылки на различные определения POSIX.zsh
/ksh93
/ FreeBSDsh
, былfalse || pkill -f asdf
быpkill
выполнен в процессе оболочки.bash
Оптимизация выполняется только тогда, когда есть только одна простая команда.true; pkill -f asdf
также будет проблемой.Ваша удаленная команда убивает себя:
pgrep и pkill игнорируют свои собственные процессы, но с флагом -f они найдут родительскую оболочку:
источник
bash -c 'pgrep -af asdf'
(без|| true
) не находит себя. Почему нет? Это имеет-f
.Вы просите pkill убить все, что соответствует "asdf". Вы должны указать, чтобы он совпадал с [a] sdf, таким образом, он все равно будет искать что-нибудь с именем «asdf», но не будет видеть себя сам (если вы выровняете asdf с [a] sdf, обратите внимание, что s выровнен с] и не с.)
Это обычная уловка, также используемая с grep / egrep / awk / etc:
Этот трюк старый, и я видел его десятилетия назад в FAQ по Unix (который до сих пор хорошо читается!)
«Автоматизировать» это нелегко, но обычно каждый раз, когда вам нужно grep для переменной string, regexp = «что-то», вы можете попробовать сделать:
источник
(abc)?(def)?
должно быть([a]bc)?([d]ef)?
... Вы не можете разобрать регулярное выражение с регулярным выражением ?! > :-)