Answers:
您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 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 shell足够聪明,可以意识到,如果通过该-c
选项传递给它的命令是一个简单命令,它可以通过不实际派生新进程来进行优化,即,它直接exec
使用简单命令,而不需要执行额外的步骤的fork
荷兰国际集团前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 -f asdf || true
这不是一个简单的命令(它是命令列表),因此无法进行上述优化,因此在运行时ssh pi@10.20.0.10 "pkill -f asdf || true"
,该sshd
进程会分叉并执行bash -c "pkill -f asdf || true"
。
正如ctx的答案所指出的那样,pkill
不会杀死自己的进程。但是,它会杀死任何其他的过程,其命令行的匹配-f
模式。该bash -c
命令匹配此模式,因此它终止了该进程–它自己的父进程(发生)。
SSH服务器随后发现它为运行远程命令而启动的Shell进程被意外杀死,因此它向SSH客户端报告错误。
x||y
一个命令列表。现在,我已经编辑了答案,以包含指向各种POSIX定义的链接。
zsh
// ksh93
FreeBSD中sh
,false || pkill -f asdf
将pkill
在shell进程中执行。bash
仅当只有一个简单命令时才执行优化。true; pkill -f asdf
也将是一个问题。
您的远程命令会杀死自己:
$ ssh 10.0.3.70 'pgrep -af asdf'
$ ssh 10.0.3.70 'pgrep -af asdf || true'
1018 bash -c pgrep -af asdf || true
pgrep和pkill将忽略它们自己的进程,但是使用-f标志,它们将找到父shell:
$ pgrep -af asdf
$ pgrep -af asdf || true
$ bash -c 'pgrep -af asdf'
$ bash -c 'pgrep -af asdf || true'
9803 bash -c pgrep -af asdf || true
bash -c 'pgrep -af asdf'
(没有|| true
)没有没有发现自己。为什么不?它有-f
。
您要求pkill杀死所有与“ asdf”匹配的东西。您应该告诉它与[a] sdf匹配,这样它仍将查找名为“ asdf”的任何内容,但看不到它本身(如果将asdf与[a] sdf对齐,请注意s与]和不是)
ssh 10.0.3.70 'pgrep -af "[a]sdf" || true'
这也是grep / egrep / awk / etc常用的技巧:
ps -ef | grep "something" # will sometimes match itself too
ps -ef | grep "[s]omething" # will not match itself
# why it works:
# the commandline contains: ps -ef | grep [s]omething
# and grep tries to find: something
这个技巧很古老,几十年前,我在Unix常见问题中看到了它(仍然很不错!)
要“自动化”它并不容易,但是通常每次您需要grep获取变量字符串regexp =“ something”时,都可以尝试执行以下操作:
grep "$(echo "${regexp}" | LC_ALL='C' sed -e 's/[a-zA-Z0-9_-]/[&]/')"
# if regexp="something", it does: grep "[s]omething"
# if regexp="otherthing", it does: grep "[o]therthing"
# if regexp="^thirdthing", it does: grep "^[t]hirdthing" #ok, kept the "^"
#BUT fails on : regexp="[abc]def", as it does: grep "[[a]bc]def" instead of grep "[abc][d]ef" ...
(abc)?(def)?
必须是([a]bc)?([d]ef)?
...您无法用正则表达式解析正则表达式?> :-)
pkill
,因为它的ARG列表中的正则表达式匹配杀死其父壳过程中,我会提出一个术语异议:x || y
是不是一个复合命令,它是一个命令列表。