Su suposición de que es en ssh
sí misma la que devuelve el estado de salida 255 es correcta. La ssh
página del manual dice que:
ssh sale con el estado de salida del comando remoto o con 255 si se produjo un error.
Si simplemente ejecutara ssh [email protected] "pkill -f asdf"
, lo más probable es que obtenga un estado de salida de 1
, correspondiente al pkill
estado de " No hay procesos coincidentes ".
La parte difícil es entender por qué ocurre un error con SSH cuando ejecuta
ssh pi@10.20.0.10 "pkill -f asdf || true"
Comandos remotos SSH
El servidor SSH lanza un shell para ejecutar comandos remotos. Aquí hay un ejemplo de esto en acción:
$ 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
Tenga en cuenta que el shell predeterminado es bash
y que el comando remoto no es un comando simple sino una tubería , "una secuencia de uno o más comandos separados por el operador de control |
".
El shell Bash es lo suficientemente inteligente como para darse cuenta de que si el comando que le pasa la -c
opción es un comando simple , puede optimizar al no bifurcar un nuevo proceso, es decir, es directamente exec
el comando simple en lugar de pasar por el paso adicional de fork
ing antes de exec
s. Aquí hay un ejemplo de lo que sucede cuando ejecuta un comando simple remoto ( ps -elf
en este caso):
$ 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
Me he encontrado con este comportamiento antes, pero no pude encontrar una referencia mejor que esta respuesta de AskUbuntu .
comportamiento de pkill
Como pkill -f asdf || true
no es un comando simple (es una lista de comandos ), la optimización anterior no puede ocurrir, por lo tanto, cuando ejecuta ssh [email protected] "pkill -f asdf || true"
, el sshd
proceso se bifurca y ejecuta bash -c "pkill -f asdf || true"
.
Como señala la respuesta de ctx, pkill
no matará su propio proceso. Sin embargo, será matar a cualquier otro proceso cuya línea de comandos coincide con el -f
patrón. El bash -c
comando coincide con este patrón, por lo que mata este proceso, su propio padre (como sucede).
El servidor SSH luego ve que el proceso de shell que inició para ejecutar los comandos remotos se cerró inesperadamente, por lo que informa un error al cliente SSH.
pkill
mata su proceso de shell principal porque su lista de argumentos coincide con la expresión regular, plantearé una objeción de terminología: nox || y
es un comando compuesto , es una lista de comandos .x||y
como una lista de comandos. Ahora he editado mi respuesta para incluir enlaces a las diversas definiciones POSIX.zsh
/ksh93
/ FreeBSDsh
,false || pkill -f asdf
se habríapkill
ejecutado en el proceso de shell.bash
solo realiza la optimización cuando solo hay un comando simple.true; pkill -f asdf
También sería un problema.Su comando remoto se suicida:
pgrep y pkill ignorarán su propio proceso, pero con el indicador -f, encontrarán el shell principal:
fuente
bash -c 'pgrep -af asdf'
(sin el|| true
) no se encuentra. Por qué no? Tiene-f
.Le pides a pkill que mate cualquier cosa que coincida con "asdf". Debería decirle que coincida con [a] sdf, de esa manera seguirá buscando algo llamado "asdf", pero no se verá a sí mismo (si alinea asdf con [a] sdf, observe que la s está alineada con] y no s.)
Es un truco común que también se usa con grep / egrep / awk / etc:
Este truco es antiguo, y lo vi hace décadas en las preguntas frecuentes de Unix (¡que sigue siendo una buena lectura!)
Para "automatizarlo", no es fácil, pero generalmente cada vez que necesita grep para una cadena variable regexp = "algo", puede intentar hacer:
fuente
(abc)?(def)?
tendrá que ser([a]bc)?([d]ef)?
... ¡¿No puedes analizar regex con regex ?! > :-)