Votre supposition que c'est ssh
lui - même qui renvoie le statut de sortie 255 est correcte. La ssh
page de manuel indique que:
ssh se ferme avec l'état de sortie de la commande à distance ou avec 255 en cas d'erreur.
Si vous deviez simplement exécuter ssh [email protected] "pkill -f asdf"
, vous obtiendriez très probablement un statut de sortie de 1
, correspondant au pkill
statut « Aucun processus correspondant ».
La partie difficile est de comprendre pourquoi une erreur se produit avec SSH lorsque vous exécutez
ssh pi@10.20.0.10 "pkill -f asdf || true"
Commandes à distance SSH
Le serveur SSH lance un shell pour exécuter des commandes à distance. Voici un exemple de ceci en action:
$ 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
Notez que le shell par défaut est bash
et que la commande distante n'est pas une simple commande mais un pipeline , "une séquence d'une ou plusieurs commandes séparées par l'opérateur de contrôle |
".
Le shell Bash est suffisamment intelligent pour se rendre compte que si la commande qui lui est passée par l' -c
option est une commande simple , il peut optimiser en ne forçant pas réellement un nouveau processus, c'est-à-dire qu'il est directement exec
la commande simple au lieu de passer par l'étape supplémentaire d’ fork
ing avant lui exec
. Voici un exemple de ce qui se passe lorsque vous exécutez une commande simple à distance ( ps -elf
dans ce cas):
$ 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
J'ai rencontré ce comportement auparavant, mais je n'ai pas pu trouver une meilleure référence autre que cette réponse AskUbuntu .
comportement pkill
Étant donné qu'il pkill -f asdf || true
ne s'agit pas d'une simple commande (c'est une liste de commandes ), l'optimisation ci-dessus ne peut pas se produire, donc lorsque vous exécutez ssh [email protected] "pkill -f asdf || true"
, le sshd
processus se déroule et s'exécute bash -c "pkill -f asdf || true"
.
Comme le souligne la réponse de ctx, pkill
ne tuera pas son propre processus. Cependant, il va tuer tout autre processus dont la ligne de commande correspond à la -f
configuration. La bash -c
commande correspond à ce modèle, donc elle tue ce processus - son propre parent (en l'occurrence).
Le serveur SSH voit alors que le processus shell qu'il a démarré pour exécuter les commandes à distance a été tué de manière inattendue, il signale donc une erreur au client SSH.
pkill
tue son processus shell parent car sa liste d'arguments correspond à l'expression rationnelle, je soulèverai une objection de terminologie: cex || y
n'est pas une commande composée , c'est une liste de commandes .x||y
comme une liste de commandes. J'ai maintenant modifié ma réponse pour inclure des liens vers les différentes définitions POSIX.zsh
/ksh93
/ FreeBSDsh
,false || pkill -f asdf
aurait étépkill
exécuté dans le processus shell.bash
ne fait l'optimisation que lorsqu'il n'y a qu'une seule commande simple.true; pkill -f asdf
serait également un problème.Votre commande à distance se tue:
pgrep et pkill ignoreront leur propre processus, mais avec le drapeau -f, ils trouveront le shell parent:
la source
bash -c 'pgrep -af asdf'
(sans le|| true
) ne se retrouve pas . Pourquoi pas? Oui-f
.Vous demandez à pkill de tuer tout ce qui correspond à "asdf". Vous devez lui dire de correspondre à [a] sdf, de cette façon, il cherchera toujours tout ce qui s'appelle "asdf", mais ne se verra pas (si vous alignez asdf avec [a] sdf, notez que le s est aligné avec] et pas l'art.)
C'est une astuce courante également utilisée avec grep / egrep / awk / etc:
Cette astuce est ancienne, et je l'ai vue il y a des décennies dans la FAQ Unix (qui est toujours une bonne lecture!)
Pour "l'automatiser", ce n'est pas facile, mais généralement à chaque fois que vous devez rechercher une chaîne variable regexp = "quelque chose", vous pouvez essayer de faire:
la source
(abc)?(def)?
devra être([a]bc)?([d]ef)?
... Vous ne pouvez pas analyser regex avec regex?! > :-)