Je vois que je peux faire
$ [ -w /home/durrantm ] && echo "writable"
writable
ou
$ test -w /home/durrantm && echo "writable"
writable
ou
$ [[ -w /home/durrantm ]] && echo "writable"
writable
J'aime utiliser la troisième syntaxe. Sont-ils équivalents à tous égards et pour tous les cas négatifs et marginaux? Existe-t-il des différences de portabilité, par exemple entre bash sur Ubuntu et sur OS X ou des versions bash antérieures / récentes, par exemple avant / après 4.0 et les expressions sont-elles développées de la même manière?
shell
posix
test
portability
Michael Durrant
la source
la source
[ … ]
vs[[ … ]]
vstest …
, il y a des réponses plus complètes dans cette question principalement en double .Réponses:
[
est synonyme detest
commande et est simultanément une commande intégrée et séparée de bash . Mais[[
est un mot clé bash et ne fonctionne que dans certaines versions. Donc, pour des raisons de portabilité, il vaut mieux utiliser un[]
ou plusieurstest
la source
[
POSIX est-il intégré ou Bash est-il intégré?test
et aux[
mêmes. Si un shell peut effectuer l'évaluation par lui-même, cela vous enregistre un processus et le rend un peu plus rapide, mais le résultat doit être identique.[
est défini par POSIX et donc extrêmement portable (ce qui semble être le but de cette question si je ne me trompe pas)[
ettest
c'est POSIX . Il semble n'y avoir ni "recommandé", bien que la seule différence (?) Que je puisse distinguer entre eux est quetest
"ne reconnaîtra pas l'argument" - "[en tant que délimiteur indiquant la fin des options]" (? - ce qui implique que " - " est reconnu comme étant une fin d'argumentation[
, ce que je ne parviens pas à trouver un bon test. Quoi qu'il en soit, je m'éloigne du sujet. Utilisez ce que vous voulez. IMO,[
c'est élégant, mais c'esttest
clairement une commande)Oui, il y a des différences. Les plus portables sont
test
ou[ ]
. Ceux-ci font tous les deux partie de la spécification POSIXtest
.La
if ... fi
construction est également définie par POSIX et doit être entièrement portable.Le
[[ ]]
est uneksh
fonctionnalité qui est également présente dans certaines versions debash
( toutes les modernes ),zsh
et peut-être dans d’autres, mais n’est pas présente danssh
ou dansdash
les divers autres coquillages plus simples.Donc, pour faire vos scripts portables, utiliser
[ ]
,test
ouif ... fi
.la source
bash
etzsh
avoir soutenu[[
pendant très longtemps (bash
ajouté à la fin des années 90,zsh
pas plus tard que 2000, et je serais surpris si jamais il manquait de support), il est donc peu probable que vous rencontriez une version sans[[
. Ildash
est beaucoup plus probable de rencontrer un autre shell compatible POSIX (tel que ).[[
est que les développements de paramètres ne doivent pas être cités:[[-f $file]]
event fonctionne si$file
contient des caractères d'espacement.[[ $a =~ ^reg.*exp.*$' ]]
S'il vous plaît noter que ce
[] && cmd
n'est pas la même chose que laif .. fi
construction.Parfois, son comportement est assez similaire et vous pouvez utiliser
[] && cmd
au lieu deif .. fi
. Mais seulement parfois. Si vous avez plus d'une commande à exécuter si condition ou si vous devezif .. else .. fi
être prudent et effacer la logique.Quelques exemples:
N'est-ce pas la même chose que
car si
ls
échouera,echo
sera exécuté ce qui ne se produira pas avecif
.Un autre exemple:
n'est pas la même chose que
bien que cette construction agisse de la même manière
s'il vous plaît noter
;
après l'écho est important et doit être là.Donc, reprenant la déclaration ci-dessus, nous pouvons dire
[] && cmd
== si la première commande réussit, exécute la suivanteif .. fi
== si condition (qui peut également être la commande test), puis exécuter la ou les commandesDonc, pour la portabilité entre
[
et[[
utiliser[
seulement.if
est compatible POSIX. Donc, si vous devez choisir entre[
etif
choisissez de regarder votre tâche et votre comportement attendu.la source
[ -z "$VAR" ] && { ls file; true; } || echo wiiii
. C'est un peu plus verbeux, mais c'est quand même plus court que laif...fi
construction.[
et enif
tant que sous-titres, mais ils ne sont pas. C'est en fait le&&
qui remplace leif
.[
exécute du code et retourne un statut, beaucoup commels
et legrep
ferait.if
L'exécution des branches dépend du statut de retour de la commande (instruction) donnée après le if, il peut s'agir de n'importe quelle commande (instruction).&&
exécute l'instruction suivante uniquement si l'instruction précédente a renvoyé 0, à la manière d'un simpleif..then..fi
.En fait,
&&
c’est le qui remplaceif
, et non letest
: uneif
instruction dans les scripts de shell vérifie si une commande a renvoyé un état de sortie "réussi" (zéro); dans votre exemple, la commande est[
.Il y a donc deux choses que vous faites varier ici: la commande utilisée pour exécuter le test et la syntaxe utilisée pour exécuter du code en fonction du résultat de ce test.
Commandes de test:
test
est une commande standardisée permettant d’évaluer les propriétés des chaînes et des fichiers; dans votre exemple, vous exécutez la commandetest -w /home/durrantm
[
est un alias de cette commande, également normalisé, qui a un dernier argument obligatoire]
pour ressembler à une expression entre crochets; ne vous laissez pas berner, c'est toujours juste une commande (vous pouvez même trouver que votre système a un fichier appelé/bin/[
)[[
est une version étendue de la commande de test intégrée à certains shells, mais ne faisant pas partie du même standard POSIX; il inclut des options supplémentaires que vous n'utilisez pas iciExpressions conditionnelles:
&&
opérateur ( normalisé ici ) effectue une opération AND logique en évaluant deux commandes et en renvoyant 0 (ce qui représente la valeur vraie) si elles renvoient toutes les deux 0; il n'évaluera la deuxième commande que si la première a retourné zéro, elle peut donc être utilisée comme simple conditionif ... then ... fi
construction ( normalisée ici ) utilise la même méthode pour juger de la "vérité", mais permet une liste composée d'instructions dans lathen
clause, plutôt que la seule commande fournie par un&&
court-circuit, et fournit des clauseselif
et deselse
articles difficiles à écrire. en utilisant seulement&&
et||
. Notez qu'il n'y a pas de crochets autour de la condition dans uneif
instruction .Les exemples suivants sont donc également portables, et entièrement équivalents, de votre exemple:
test -w /home/durrantm && echo "writable"
[ -w /home/durrantm ] && echo "writable"
if test -w /home/durrantm; then echo "writable"; fi
if [ -w /home/durrantm ]; then echo "writable"; fi
Bien que les éléments suivants soient également équivalents, mais moins portables, en raison de la nature non standard de
[[
:[[ -w /home/durrantm ]] && echo "writable"
if [[ -w /home/durrantm ]]; then echo "writable"; fi
la source
Pour la portabilité, utilisez
test
/[
. Mais si vous n'avez pas besoin de la portabilité, par souci de santé mentale et vis-à-vis des autres lecteurs de votre script, utilisez-le[[
. :)Voir aussi
What is the difference between test, [ and [[ ?
dans le BashFAQ .la source
Si vous souhaitez une portabilité hors du monde semblable à Bourne, alors:
est le plus portable. Cela fonctionne dans les coquilles de la Bourne,
csh
et lesrc
familles.la production physique au
"writable"
lieu dewritable
dans les coquilles de larc
famille (rc
,es
,akanga
, où"
est pas spécial).ne fonctionnerait pas dans les coquilles de
csh
ou desrc
familles sur des systèmes sans[
commande$PATH
(certaines sont connues pour avoir,test
mais pas son[
alias).ne fonctionne que dans les coquillages de la famille Bourne.
ne fonctionne que dans
ksh
(où il est originaire),zsh
etbash
(tous les 3 dans la famille Bourne).Aucun ne fonctionnerait dans la
fish
coquille où vous avez besoin:ou:
la source
La raison la plus importante pour laquelle je choisis de choisir l’un
if foo; then bar; fi
ou l’ autrefoo && bar
est de savoir si le statut de sortie de l’ensemble de la commande est important.comparer:
avec:
Vous pourriez penser qu'ils font la même chose; Toutefois, si
foo
échoue (ou est false, selon votre point de vue), alors, dans le premier exemple, do_baz ne sera pas exécuté, car le script sera terminé ... Leset -e
shell ordonne à l'enveloppe de se terminer immédiatement si une commande renvoie un statut faux. Très utile si vous faites des choses comme:Vous ne voulez pas que le script continue à s'exécuter en cas d'
cd
échec pour une raison quelconque.la source
foo
n'abandonnera pas le script dans les deux cas. C'est un cas spécial pourset -e
(lorsque la commande est évaluée en tant que condition (à gauche de certaines conditions && / || ou dans les conditions if / while / Until / elsif ...). Un échecbar
sortirait du shell dans les deux cas.cd /some/directory && rm -rf -- *
oucd /some/directory || exit; rm -rf -- *
(ne supprime toujours pas les fichiers cachés). Personnellement, je n'aime pas l'idée d'utiliserset -e
comme excuse pour ne pas faire un effort pour écrire le code correct.