Comment fonctionne exactement “/ bin / [”?

50

Je suis toujours surpris qu'il /biny ait un [programme dans le dossier .

Est-ce ce qu'on appelle quand on fait quelque chose comme if [ something ]:?

En appelant [explicitement le programme dans un shell, il demande une correspondance ], et lorsque je fournis le crochet de fermeture, il semble ne rien faire, peu importe ce que j'insère entre les crochets.

Inutile de dire que la manière habituelle d'obtenir de l'aide à propos d'un programme ne fonctionne pas, c'est-à-dire que ni man [ne [ --helpfonctionne.

Bregalad
la source
11
@IporSircer [fait référence à la testcommande si, non expr, il devrait donc êtreman test
Sergiy Kolodyazhnyy
8
man '['fonctionne très bien pour moi - soit vous avez oublié de citer [ou vous avez une définition différente de «œuvres».
Toby Speight
3
Quelques avertissements: [évalue ses arguments, vous devez donc laisser des espaces entre eux. [ a=b ]n’est pas une comparaison: ce sera toujours vrai (c’est une seule chaîne: "a = b", qui est toujours évalué à vrai ). Et vous devriez limiter le nombre d’arguments à 4 (même si les implémentations récentes permettent plus .. Limiter à 4 le rend plus portable.Par exemple: a [ "a" = "b" ]déjà 4 arguments: "a" "=" "b" et la fin non nécessaire du test arg: "]"). Si vous avez besoin de plus: tests en chaîne avec par exemple:if [ "$Var_a" = "foo" ] && [ "$Var_b" = "bar" ] ; then : do something ; fi
Olivier Dulac
1
@OlivierDulac a !lui-même (non échappé et non cité) ne sera pas remplacé, et ce serait encore mieux if ! [ .... Toutes les extensions de bash qui utilisent !incluent au moins un autre caractère
muru
3
Vous devriez également noter qu'il y a aussi un [-builtin dans bash(et éventuellement d'autres shells), et que cela peut être utilisé à la place de /bin/[. Il existe également la testcommande-qui, sur de nombreux systèmes, est un lien symbolique vers /bin/[(ou vice-versa) - mais sur d'autres, il s'agit d'une commande séparée.
Baard Kopperud

Réponses:

63

Le [travail de la commande consiste à évaluer les expressions de test. Il retourne avec un statut de sortie 0 (ce qui signifie vrai ) lorsque l'expression est résolue en vrai et quelque chose d'autre (ce qui signifie faux ) sinon.

Ce n'est pas qu'il ne fait rien, c'est juste que son résultat se trouve dans son statut de sortie. Dans un shell, vous pouvez connaître l'état de sortie de la dernière commande $?pour les shells de type Bourne ou $statusdans la plupart des autres shells (fish / rc / es / csh / tcsh ...).

$ [ a = a ]
$ echo "$?"
0
$ [ a = b ]
$ echo "$?"
1

Dans d'autres langues perl, l'état de sortie est par exemple renvoyé dans la valeur de retour de system():

$ perl -le 'print system("[", "a", "=", "a", "]")'
0

Notez que tous les shells modernes Bourne-like (et fish) ont une [commande intégrée . Celui dans /binne sera généralement exécuté que lorsque vous utilisez un autre shell ou lorsque vous faites des choses comme env [ foo = bar ]ou find . -exec [ -f {} ] \; -printou cette perlcommande ci-dessus ...

La [commande est également connue sous son testnom. Lorsqu'il est appelé en tant que test, il ne nécessite pas d' ]argument de clôture .

Bien que votre système ne dispose peut-être pas de page de manuel [, il en a probablement une test. Mais encore une fois, notez qu'il documenterait la /bin/[ou la /bin/testmise en œuvre. Pour en savoir plus sur la [structure de votre shell, vous devriez plutôt lire la documentation de votre shell.

Pour plus d'informations sur l'historique de cet utilitaire et sur la différence avec l' [[...]]expression de test ksh, vous pouvez consulter cet autre Q & R ici .

Stéphane Chazelas
la source
Bon, comme d'habitude. Vous voudrez peut-être ajouter les commentaires que j'ai ajoutés sous la question @Bregalad? ou peut-être d'autres supplémentaires? Ainsi, la réponse sera encore plus complète sur "comment ça marche exactement" (je remarque que vous avez déjà donné une information plus précise sur "]" que moi ^^)
Olivier Dulac
«Tous les coquillages (comme les poissons) ressemblant à Bourne ont une commande [intégrée». C'est vrai dans la pratique au 21ème siècle, mais je suis à peu près sûr que j'ai utilisé un coquillage sans [. Je ne me souviens pas s'il s'agissait d'une variante Bourne ou d'une version ancienne de frêne.
Gilles 'SO- arrête d'être méchant'
@Gilles Le shell Bourne implémenté à la fois [et testintégré à Unix System III. Avant cela, il n'y en avait pas [et il n'y testavait qu'une commande binaire externe.
Jlliagre
@Gilles, les cendres d'origine avaient été testés (fusionnés avec expr), mais facultativement . Selon in-ulm.de/~mascheck/various/ash , les tests BSD n'avaient pas été testés avant environ 2000. J'ai ajouté "moderne".
Stéphane Chazelas
Pourquoi dans le monde voudriez-vous faire find . -exec [ f {} ] \; -print? La commande find . -type f -printferait la même chose tellement plus efficacement ...
Ce n'est pas mon vrai nom
41

Je suis toujours surpris qu'il /biny ait un [programme dans le dossier .

Vous avez raison d'être surpris. C’est l’une des rares commandes POSIX, avec l’utilitaire null ( :), qui ne respecte pas la convention des caractères autorisés du fichier de commandes (jeu de caractères du nom de fichier portable).

Est-ce que c'est ce qu'on appelle quand on fait quelque chose comme if [ something ]:?

Précisément mais il peut être utilisé sans le iftrop.

En appelant [explicitement le programme dans un shell, il demande une correspondance ], et lorsque je fournis le crochet de fermeture, il semble ne rien faire, peu importe ce que j'insère entre les crochets.

Il ne fait rien de visible, mais il fait exactement la même chose que lorsqu'il est utilisé avec if, c'est-à-dire qu'il définit le statut de sortie à 0 (vrai) ou à toute autre chose (faux) en fonction de ce que vous mettez entre crochets. C'est (pour une raison) le même comportement que la testcommande; la seule différence est qu'il cherche la fin ]. Voir man testpour plus de détails.

Inutile de dire que la manière habituelle d'obtenir de l'aide à propos d'un programme ne fonctionne pas, c'est-à-dire que ni man [ne [ --helpfonctionne.

Cela dépend de votre système d'exploitation. man [Cela fonctionne certainement pour moi sur quelques distributions Gnu / Linux classiques, mais pas sur Solaris.

[ --helpCela peut fonctionner ou non, selon l’implémentation car il enfreint la syntaxe de toute façon, il manque la fin ]. De plus, la norme POSIX pour la test/ [commande exclut explicitement toutes les options, y compris la --résiliation de l' option afin que les deux [ --help ]et le test --helpbesoin de revenir trueet se taire par la conception. Notez que ce que vous mettez à l' intérieur des crochets ou après [et qui ressemblent à des options (par exemple -f file, -n stringet les goûts) ne sont pas des options mais opérandes .

Tous les interprètes shell de style moderne Bourne (comme bash, ksh, dashet zshpour ne citer que quelques - uns) mettre en œuvre le test/ [utilitaire en interne comme un builtin donc quand vous les utilisez, la bonne page de manuel pour désigner pourrait être celui de la coquille, pas testun.

Avant Unix System III (1981), le shell Bourne testn’implémentait pas l’ utilitaire en interne, de sorte que seule l’implémentation de commande binaire externe était disponible. Il n'y avait pas non plus de [commande (interne ou intégrée) avant Unix System III. Par exemple, sous Unix Version 7, vous deviez taper:

if test something ; then

au lieu de:

if [ something ] ; then
jlliagre
la source
"man [fonctionne définitivement pour moi sur les distributions grand public Gnu / Linux" Hmm .. Centos (il est vrai que 6,8 encore) n'est clairement pas assez grand public :) man testfonctionne mais pas man [ Par contre, mon environnement cygwin est connu man [!
Adam
1
@Adam Oui, vous avez raison, c'est plus récent que je ne le pensais bien que je n'ai pas écrit toutes les distributions Linux classiques, mais que cela a fonctionné pour moi (c'est-à-dire celles que j'ai testées). C’est le clone OL 7.2 (RHEL 7.2) et Mint 17.1 (Ubuntu 14.04).
jeudi
man [ne semble pas fonctionner sur Manjaro (basé sur Arch Linux). Le manuel des testlistes [ --helpest une invocation valide qui devrait afficher de l'aide, mais il est intéressant de noter qu'il ne le fait pas et se plaint plutôt d'une absence ], comme c'est le cas avec --version. L'ajout de ]ne fait rien, donc il semble impossible d'obtenir de l'aide autrement que de man test.
Darkhogg
@Darkhogg Vous pouvez essayer /usr/bin/[ --helpou /bin/[ --help.
jeudi
1
@jlliagre Vous avez tout à fait raison, j'utilisais les fonctions intégrées. env [ --helpainsi que de /usr/bin/[ --helptravailler complètement bien (même si je dois citer /usr/bin/[ou zsh se plaint).
Darkhogg
10

[est en fait plus communément appelé testcommande. L’utilisation typique de cette commande consiste simplement à évaluer des expressions et à renvoyer leur condition - vraie ou fausse. Il est souvent utilisé dans les if-then-else-fiinstructions, même s'il peut être utilisé en dehors des ifinstructions pour exécuter conditionnellement d'autres commandes via un shell &&ou des ||opérateurs, comme cela.

$ [ -e /etc/passwd  ] && echo "File exists"
File exists

$ test -e /etc/passwd && echo "File exists"
File exists

Plus spécifiquement, l'évaluation est communiquée à d'autres commandes via le statut de sortie. Certains programmes peuvent choisir de générer un état de sortie pour indiquer différents types d'événements: exécution réussie du programme, erreur d'un type particulier survenant pendant l'exécution ou erreurs de syntaxe. Dans le cas de la testcommande, il y a des 0significations vraies et 1fausses. Comme Stephan l’a souligné, les erreurs de syntaxe produisent le statut de sortie 2.

Son emplacement dépend de votre système et explique également pourquoi vous n'avez pas vu la page de manuel à ce moment-là man [. Par exemple, sur FreeBSD, il est en dessous /bin. Sous Linux (ou dans mon cas particulier, Ubuntu 16.04), il se trouve dans /usr/bin/. Si vous le faites man [ou man testsur un système Linux, vous verrez la même documentation ouverte. Il est également important de noter que votre shell peut avoir sa propre implémentation test.

Il convient également de noter que cette commande pose des problèmes que l’implémentation de Korn Shell (connue sous le nom de "expression conditionnelle" avec des doubles crochets [[ "$USER" = "root" ]]) cherche à résoudre. Cette fonctionnalité est également utilisée par d'autres coques telles que bashet zsh.

Sergiy Kolodyazhnyy
la source
/usr/bin/pour Amazon Linux aussi.
franklinsijo
@ StéphaneChazelas Merci. Réponse modifiée en conséquence
Sergiy Kolodyazhnyy
3

Ni man [ni [ --helpfonctionne

Sur certaines distributions (par exemple Ubuntu), man [suit un lien symbolique vers test(1). Sur d'autres (par exemple Arch), ce n'est pas le cas. (Mais la testpage de manuel documente également l'utilisation [)


type -a [ vous montre qu'il existe à la fois un shell intégré et un exécutable.

$ type -a [
[ is a shell builtin
[ is /usr/bin/[

bash-builtin [ --helpimprime simplement un message d'erreur. (Mais comme il s'agit d'une commande intégrée, vous pouvez utiliser help [ou consulter la page de manuel / docs de bash).

/usr/bin/[ --help affiche l’aide complète (pour la version de GNU Coreutils), qui commence par:

$ /usr/bin/[ --help
Usage: test EXPRESSION
  or:  test
  or:  [ EXPRESSION ]
  or:  [ ]
  or:  [ OPTION
Exit with the status determined by EXPRESSION.

      --help     display this help and exit
      --version  output version information and exit

et décrit ensuite la syntaxe autorisée pour EXPRESSION.

C'est une autre façon dont vous auriez pu découvrir cela [et qui testsont équivalentes.


En passant, si vous programmez pour bash (ou écrivez des lignes uniques de manière interactive), je le recommanderais [[au lieu de [. C'est mieux à plusieurs égards, voir les liens dans la réponse de Serg.

Peter Cordes
la source
2

[La commande retourne l'état de sortie zéro si expression, contenue dans ses arguments, est considérée comme vraie et non nulle comme état de sortie si expression, contenue dans ses arguments, est considérée comme fausse. Il échoue également avec le message d'erreur si son dernier argument n'est pas ](ceci est fait uniquement pour des raisons esthétiques).

Par exemple:

[ hello ]
echo "Exit-status of [ hello ] is:" $?
[ abc = abc ]
echo "Exit-status of [ abc = abc ] is:" $?
[ ]
echo "Exit-status of [ ] is:" $?
[ abc = def ]
echo "Exit-status of [ abc = def ] is:" $?

… Produira:

Le statut de sortie de [hello] est: 0       - car la chaîne non vide est considérée comme vraie 
. Le statut de sortie de [abc = abc] est: 0   - car 'abc' est vraiment identique à 'abc' Le 
statut de sortie de [] est : 1             - car la chaîne vide est considérée comme fausse 
. Le statut de sortie de [abc = def] est: 1   - parce que 'abc' diffère vraiment de 'def'

Cependant, bash et de nombreux autres shells n'appellent généralement pas /bin/[(ou /usr/bin/[) dans ces cas-là, mais appellent une commande intégrée avec exactement le même comportement (uniquement pour des raisons de performances). Pour appeler /bin/[(et non le substitut intégré au shell), vous devez spécifier explicitement son chemin (par exemple /bin/[ hello ], vous n'avez pas besoin de préfixer ]avec dirname si ☺ ), ou configurer le shell pour ne pas utiliser un substitut intégré (par exemple, enable -n [en bash).

PS: Comme cela a été dit dans d'autres réponses, [est lié à test. Mais test, contrairement à [, ne nécessite pas ]le dernier argument (et ne l'attend pas du tout; l'ajout ]d' testarguments supplémentaires peut entraîner l'échec du message d'erreur ou le renvoi d'un résultat erroné) . Le /bin/testet /bin/[peut résoudre le même fichier (par exemple , un est un lien symbolique , dans ce cas , le détournement de comportement est probablement mis en œuvre par l' analyse de la commande actuellement appelée dans le test/ [code lui - même) ou des fichiers différents. En testoutre, shell appelle généralement le substitut intégré, sauf si path est explicitement spécifié ( /bin/test) ou s'il est configuré pour ne pas le faire (enable -n test)

PPS: Contrairement à testand [, modern ifn’est jamais un vrai fichier. Cela fait partie de shell (par exemple bash) syntaxe: if commandA; then commandB; fi(sauts de ligne peuvent être utilisés à la place des points - virgules) provoque commandBà exécuter si et seulement si vous êtes commandAliquide' zéro état. Cela correspond parfaitement au comportement de testou [, permettant de les combiner comme if [ "$a" = foo ]; then …; fi (ou if test "$a" = foo; then …; fi- tout simplement moins lisibles) . Cependant, les scripts modernes utilisent souvent à la [[place de testou [, qui (en tant que if) n'est jamais un fichier réel, mais fait toujours partie de la syntaxe du shell.

PPPS: En ce qui concerne man- ne vous attendez jamais manà avoir un article sur chaque commande de votre système de fichiers. Infos sur certaines commandes (même « réel », basé sur des fichiers) peuvent être manquants, informations sur certains shell Encastrements peut - être présent non seulement dans un article consacré à l' enveloppe spécifique (qui est l'endroit où vous certainement y trouver des informations sur test, [, if, [[). Pourtant, beaucoup de distributions ont des manarticles explicites pour testet [. (À propos --help, ce n'est pas reconnu testpour une raison évidente: il doit gérer des cas comme par exemple a=--help; test "$a": sur certaines distributions [ --help(sans fermer ]), l'aide est toujours affichée, sur d'autres non.)

sasha
la source
3
Notez que ifc'était une commande jusqu'à Unix V6. Unix V7 (1979) est venu avec le shell Bourne (avec sa if-then-else-ficonstruction) et la nouvelle testcommande.
Stéphane Chazelas