OR con verdadero en un comando sobre ssh

OR con verdadero en un comando sobre ssh

Cuando intento ejecutar pkill -fde forma remota a través de ssh e intento descartar el posible código de error (para continuar con el resto de mi script incluso si no se encuentra ningún proceso), || trueno se comporta como esperaba.

$ pkill asdf || true
$ echo $?
0
$ pkill -f asdf || true
$ echo $?
0
$ ssh [email protected] "pkill asdf || true"
$ echo $?
0
$ ssh [email protected] "pkill -f asdf || true"
255

Supongo que esssheso devuelve 255, no el comando entre comillas, pero ¿por qué?

Respuesta1

Su suposición de que es sshél mismo el que devuelve el estado de salida 255 es correcta. La sshpágina de manual establece que:

ssh sale con el estado de salida del comando remoto o con 255 si ocurrió un error.

Si simplemente ejecutara , lo más probable es que obtendría un estado de salida de , correspondiente al estado de "ssh [email protected] "pkill -f asdf"1pkillNingún proceso coincide”.

La parte desafiante es entenderpor quése produce un error con SSH al ejecutar

ssh [email protected] "pkill -f asdf || true"

Comandos remotos SSH

El servidor SSH inicia 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 bashy que el comando remoto no es un comando simple sino untuberí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 -copción es uncomando simple, se puede optimizar sin bifurcar un nuevo proceso, es decir, directamente execcon el comando simple en lugar de realizar el paso adicional de forking antes de hacerlo exec. A continuación se muestra un ejemplo de lo que sucede cuando ejecuta un comando simple remoto ( ps -elfen 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 encontré con este comportamiento antes pero no pude encontrar una referencia mejor que no seaesta respuesta de AskUbuntu.

comportamiento pkill

Dado que pkill -f asdf || trueno es un comando simple (es unlista de comandos), la optimización anterior no puede ocurrir, por lo que cuando se ejecuta , el proceso se bifurca y se ejecuta .ssh [email protected] "pkill -f asdf || true"sshdbash -c "pkill -f asdf || true"

Como señala la respuesta de ctx, pkillno eliminará su propio proceso. De todos modos, esovoluntadelimine cualquier otro proceso cuya línea de comando coincida con el -fpatrón. El bash -ccomando coincide con este patrón, por lo que finaliza este proceso: su propio padre (como sucede).

Luego, el servidor SSH ve que el proceso de shell que inició para ejecutar los comandos remotos se eliminó inesperadamente, por lo que informa un error al cliente SSH.

Respuesta2

Su comando remoto se suicida:

$ 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 y pkill ignorarán su propio proceso, pero con el indicador -f, encontrarán el shell principal:

$ 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

Respuesta3

Le pides a pkill que elimine cualquier cosa que coincida con "asdf". Deberías decirle que coincida con [a]sdf, de esa manera seguirá buscando cualquier cosa llamada "asdf", pero no se verá a sí mismo (si alineas asdf con [a]sdf, observa que la s está alineada con ] y no s.)

ssh 10.0.3.70 'pgrep -af "[a]sdf" || true'

Es un truco común que también se usa con 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

Este truco es antiguo y lo vi hace décadas en las preguntas frecuentes de Unix (¡que todavía es una buena lectura!)

"Automatizarlo" no es fácil, pero normalmente cada vez que necesitas buscar una cadena variable regexp="algo", puedes intentar hacer:

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" ...

información relacionada