Est-il possible de conserver le dernier état de sortie de commande ( $?
) inchangé après un test?
Par exemple, je voudrais faire:
command -p sudo ...
[ $? -ne 1 ] && exit $?
Le dernier exit $?
doit retourner le statut de sortie sudo, mais à la place il retourne toujours 0
(le code de sortie du test).
Est-il possible de le faire sans variable temporaire?
Un autre exemple pour clarifier davantage:
spd-say "$@"
[ $? -ne 127 ] && exit $?
Dans ce cas, je veux quitter uniquement si la première commande est trouvée (code de sortie! = 127
). Et je veux quitter avec le spd-say
code de sortie réel (ce n'est peut-être pas le cas
0
).
EDIT: J'ai oublié de mentionner que je préfère une solution de réclamation POSIX pour une meilleure portabilité.
J'utilise cette construction dans des scripts où je veux fournir des alternatives pour la même commande. Par exemple, consultez mon script crc32 .
Le problème avec les variables temporaires est qu'elles peuvent masquer d'autres variables et pour éviter que vous ne deviez utiliser des noms longs, ce qui n'est pas bon pour la lisibilité du code.
la source
if ! command -p sudo; then exit; fi
ce qui aurait les mêmes résultats pour votre exemple.[ $? -ne 127 ] && exit $?
)sudo
commande réussit (c'est-à-dire s'il sesudo
termine avec le statut 0). Mais, dans votre code, le script continue de s'exécuter (ne se ferme pas) en cas desudo
succèscommand
et passudo
du tout. C'est ce que signifie que je veux quitter uniquement si la première commande est trouvée (code de sortie! = 127) et est un retour spécifiécommand
lorsque la commande qu'il appelle n'est pas trouvée. Je suppose que le problème est que l'invocationsudo
dans le cadre du test permet en premier lieu d'sudo
écraser le retourcommand
et donc de biaiser le test.Réponses:
$_
travaillera en (au moins) interactivedash
,bash
,zsh
,ksh
(mais apparemment pas dans une instruction conditionnelle à la demande) et desmksh
obus. De ceux-là - à ma connaissance - seulementbash
et lezsh
rempliront également dans un shell scripté. Ce n'est pas un paramètre POSIX - mais il est assez portable pour tout shell moderne et interactif.Pour une solution plus portable, vous pouvez faire:
Ce qui vous permet essentiellement d'étendre la valeur initiale
$?
dans la queue du script avant même de tester sa valeur à sa tête.Mais de toute façon, puisque vous semblez tester si la commande
sudo
peut être trouvée dans la chaîne de-p
chemin portable intégrée du shell aveccommand
, je pense que vous pourriez y aller un peu plus directement. En outre, pour être clair,command
ne sera pas tester l'emplacement des arguments àsudo
- il est doncsudo
- et rien n'invoque - ce qui est pertinent à cette valeur de retour.Et de toute façon, si c'est ce que vous essayez de faire:
... fonctionnerait très bien en tant que test sans risque d'erreur dans les
sudo
exécutions de commandes renvoyant d'une manière qui pourrait fausser les résultats de votre test.la source
Il existe différentes options pour gérer le statut de sortie de manière fiable sans surcharge, en fonction des besoins réels.
Vous pouvez enregistrer l'état de sortie à l'aide d'une variable:
Vous pouvez directement vérifier le succès ou l'échec:
Ou utilisez une
case
construction pour différencier le statut de sortie:avec le cas particulier posé dans la question:
Toutes ces options ont l'avantage d'être conformes à la norme POSIX.
(Remarque: à titre d'illustration, j'ai utilisé les
echo
commandes ci-dessus; remplacez-les par desexit
instructions appropriées pour correspondre à la fonction demandée.)la source
("$(get_errnos)")
est un ajout artificiel d'une substitution de commande où des comparaisons avec les codes d'erreur réels sont demandées dans la question, 2.) Il y a clairement dans la norme ce qui change$?
(et donc ce qui ne le change pas), et 3.) là il n'y a pas d'effets secondaires avec cette construction (sauf si, comme vous l'avez fait, vous les introduisez inutilement). - OTOH, puisque cela vous dérange, l'autre réponse que vous préférez est clairement non standard.$(get_errnos)
code artificiel à d'autres solutions (( exit 42 ); test "$(get_errnos)" -ne $? && echo $_
), elles ne fonctionnent pas non plus. (Vous avez préféré mettre ma solution standard en faux crédit, pas les autres hack (s) non standard .) - Bien sûr, vous pouvez ajouter du code arbitraire à toutes les réponses et le gâcher. - Et WRT au changement de$?
; ce n'est pas parce que vous ne le trouvez pas que ce n'est pas vrai. (J'ai déjà fourni dans nos discussions même les mots-clés à rechercher dans POSIX.)zsh
( mentionné pour la première fois; vous avez également ajouté plus tarddash
), que je pense que cela doit être un bogue, étant donné que l'case
état de sortie et le paramètre de$?
semblent bien définis dans POSIX. - Et ici aussi, encore une fois, vous appliquez des doubles standards; l'autre hack, par exemple, n'est ni standard, ni ne fonctionne de manière fiable dans d'autres shells standard (par exemple pas dansksh
). - Mes propositions sont standard et fonctionnent dansbash
(principalement utilisé sous Linux) etksh
(le shell prédominant dans les Unix commerciaux).Use
$_
, qui se développe jusqu'au dernier argument de la commande précédente.la source
$?
et$_
. À mon humble avis, il est préférable de s'en tenir à une méthode cohérente qui fonctionne dans d'autres cas (et peut également aider à la lisibilité du code).case
modèles , le seul endroit qui importerait en théorie (mais pas dans la question donnée), est un cas construit. - Dans tous les cas, votre substitution de commande shell propagerait le résultat de la commande intégrée, généralement d'autres extensions n'affecteront pas l'état de retour de toute façon s'il n'y a pas de commandes impliquées qui peuvent créer des erreurs (x=${a!b}
cas d' esprit , mais non pertinents ici). - Que voulez-vous dire par "commande sans nom de commande" ?Vous pouvez définir (et utiliser) une fonction shell:
alors
On peut dire que cela "triche", car il en fait une copie
$?
dans lacheck_exit_status
liste des arguments.Cela peut sembler un peu gênant, et ça l'est. (Cela se produit parfois lorsque vous imposez des contraintes arbitraires aux problèmes.) Cela peut sembler inflexible, mais ce n'est pas le cas. Vous pouvez rendre
check_exit_status
plus complexe, en ajoutant des arguments qui lui indiquent quel (s) test (s) faire sur la valeur d'état de sortie.la source
Pour répondre à votre question directe, non, il n'est pas possible de ne pas la
$?
modifier. Et c'est l'un de ces cas où je soupçonne que vous vous concentrez sur le mauvais problème. Une variable temporaire est le moyen standard et préféré d'obtenir l'effet que vous recherchez. C'est tellement standard que je suggérerais d'abandonner (ou de repenser) quelle que soit la raison que vous pensez avoir pour ne pas vouloir en utiliser un; Je doute fortement que cela vaille la complexité supplémentaire ajoutée par toute autre méthode.Si vous demandez simplement par simple curiosité, la réponse est non.
la source
$?
ou quelque chose comme ça?Voici mon extrait de code pour conserver un état de sortie précédent sans quitter le script / shell actuel
la source