37 votes

Quelle est la différence entre Shell builtin et Shell mot clé ?

Lorsque je lance ces deux commandes, j'obtiens

$ type cd
cd is a shell builtin
$ type if
if is a shell keyword

Il est clairement démontré que cd est un Shell builtin et if est un mot-clé Shell. Quelle est donc la différence entre le buildin Shell et le mot-clé ?

55voto

gniourf_gniourf Points 5285

Il y a une grande différence entre un buildin et un mot-clé, dans la façon dont Bash analyse votre code. Avant de parler de cette différence, dressons une liste de tous les mots-clés et builtins :

Constructions :

$ compgen -b
.         :         [         alias     bg        bind      break     
builtin   caller    cd        command   compgen   complete  compopt   
continue  declare   dirs      disown    echo      enable    eval      
exec      exit      export    false     fc        fg        getopts   
hash      help      history   jobs      kill      let       local     
logout    mapfile   popd      printf    pushd     pwd       read      
readarray readonly  return    set       shift     shopt     source    
suspend   test      times     trap      true      type      typeset   
ulimit    umask     unalias   unset     wait                          

Mots-clés :

$ compgen -k
if        then      else      elif      fi        case      
esac      for       select    while     until     do        
done      in        function  time      {         }         
!         [[        ]]        coproc              

Notez que, par exemple [ est un buildin et que [[ est un mot-clé. Je vais utiliser ces deux-là pour illustrer la différence ci-dessous, car ce sont des opérateurs bien connus : tout le monde les connaît et les utilise régulièrement (ou devrait le faire).

Un mot-clé est analysé et compris par Bash très tôt dans son analyse syntaxique. Cela permet par exemple ce qui suit :

string_with_spaces='some spaces here'
if [[ -n $string_with_spaces ]]; then
    echo "The string is non-empty"
fi

Cela fonctionne bien, et Bash affichera volontiers

The string is non-empty

Notez que je n'ai pas cité $string_with_spaces . Considérant ce qui suit :

string_with_spaces='some spaces here'
if [ -n $string_with_spaces ]; then
    echo "The string is non-empty"
fi

montre que Bash n'est pas heureux :

bash: [: too many arguments

Pourquoi cela fonctionne-t-il avec des mots-clés et pas avec des modules intégrés ? parce que lorsque Bash analyse le code, il voit [[ qui est un mot-clé, et comprend très tôt qu'il est spécial. Donc il va chercher la fermeture ]] et traitera l'intérieur d'une manière spéciale. Un builtin (ou commande) est traité comme une commande réelle qui va être appelée avec des arguments. Dans ce dernier exemple, bash comprend qu'il doit exécuter la commande [ avec des arguments (affichés un par ligne) :

-n
some
spaces
here
]

puisque l'expansion des variables, la suppression des guillemets, l'expansion des noms de chemin et le découpage des mots se produisent. La commande [ s'avère être construit dans le Shell, il l'exécute donc avec ces arguments, ce qui entraîne une erreur, d'où la plainte.

En pratique, vous verrez que cette distinction permet un comportement sophistiqué, qui ne serait pas possible avec des builtins (ou des commandes).

Mais en pratique, comment distinguer un buildin d'un mot-clé ? C'est une expérience amusante à réaliser :

$ a='['
$ $a -d . ]
$ echo $?
0

Lorsque Bash analyse la ligne $a -d . ] il ne voit rien de spécial (c'est-à-dire pas d'alias, pas de redirections, pas de mots-clés), il se contente donc d'effectuer l'expansion des variables. Après l'expansion des variables, il voit :

[ -d . ]

exécute donc la commande (builtin) [ avec des arguments -d , . et ] ce qui, bien sûr, est vrai (cela ne fait que tester si . est un répertoire).

Maintenant, regardez :

$ a='[['
$ $a -d . ]]
bash: [[: command not found

Oh. C'est parce que lorsque Bash voit cette ligne, il ne voit rien de spécial, et donc développe toutes les variables, et finit par voir :

[[ -d . ]]

À ce moment-là, les expansions d'alias et le balayage des mots-clés ont été effectués depuis longtemps et ne le seront plus, donc Bash essaie de trouver la commande appelée [[ ne le trouve pas, et se plaint.

Dans le même ordre d'idées :

$ '[' -d . ]
$ echo $?
0
$ '[[' -d . ]]
bash: [[: command not found

et

$ \[ -d . ]
$ echo $?
0
$ \[[ -d . ]]
bash: [[: command not found

L'expansion d'Alias est aussi quelque chose d'assez spécial. Vous avez tous fait ce qui suit au moins une fois :

$ alias ll='ls -l'
$ ll
.... <list of files in long format> ....
$ \ll
bash: ll: command not found
$ 'll'
bash: ll: command not found

Le raisonnement est le même : l'expansion des alias se produit bien avant l'expansion des variables et la suppression des guillemets.


Mot-clé vs. Alias

Maintenant, que pensez-vous qu'il se passe si nous définissons un alias comme étant un mot-clé ?

$ alias mytest='[['
$ mytest -d . ]]
$ echo $?
0

Oh, ça marche ! donc les alias peuvent être utilisés pour aliaser des mots clés ! c'est bon à savoir.


Conclusion : builtins vraiment se comportent comme des commandes : ils correspondent à une action en cours d'exécution avec des arguments qui subissent une expansion directe de la variable, le découpage des mots et le globbing. En fait, c'est comme avoir une commande externe quelque part dans le fichier /bin ou /usr/bin qui est appelé avec les arguments donnés après l'expansion des variables, etc. Notez que lorsque je dis c'est vraiment comme avoir une commande externe Je veux seulement dire en ce qui concerne les arguments, le découpage des mots, le globbing, l'expansion des variables, etc. Un buildin peut modifier l'état interne du Shell !

Les mots-clés, en revanche, sont analysés et compris très tôt, et permettent un comportement sophistiqué du Shell : le Shell pourra interdire le découpage des mots ou l'expansion des noms de chemin, etc.

Maintenant, regardez la liste des builtins et des mots-clés et essayez de comprendre pourquoi certains doivent être des mots-clés.


! est un mot-clé. Il semble qu'il serait possible d'imiter son comportement avec une fonction :

not() {
    if "$@"; then
        return 1
    else
        return 0
    fi
}

mais cela interdirait des constructions comme :

$ ! ! true
$ echo $?
0

(dans ce cas, je veux dire not ! true qui ne fonctionne pas) ou

$ ! { true; }
echo $?
1

Idem pour time Il est plus puissant d'en faire un mot-clé, de sorte que les commandes composées complexes et les pipelines avec redirections puissent être chronométrés :

$ time grep '^#' ~/.bashrc | { i=0; while read -r; do printf '%4d %s\n' "$((++i))" "$REPLY"; done; } > bashrc_numbered 2>/dev/null

Si time alors qu'une simple commande (même intégrée), elle ne verrait que les arguments grep , ^# et /home/gniourf/.bashrc La sortie de la commande est ensuite envoyée dans les autres parties du pipeline. Mais avec un mot-clé, Bash peut tout gérer ! il peut time le pipeline complet, y compris les redirections ! Si time était un simple ordre, nous ne pourrions pas le faire :

$ time { printf 'hello '; echo world; }

Essayez-le :

$ \time { printf 'hello '; echo world; }
bash: syntax error near unexpected token `}'

Essayez de le réparer ( ?):

$ \time { printf 'hello '; echo world;
time: cannot run {: No such file or directory

Sans espoir.


Mot-clé ou alias ?

$ alias mytime=time
$ alias myls=ls
$ mytime myls

Que pensez-vous qu'il se passe ?


Vraiment, un intégré est comme une commande, sauf qu'il est construit dans le Shell, alors qu'un mot-clé est quelque chose qui permet un comportement sophistiqué ! nous pouvons dire que cela fait partie de la grammaire du Shell.

9voto

Sparhawk Points 6620

man bash les appelle SHELL BUILTIN COMMANDS . Ainsi, un "Shell builtin" est juste comme une commande normale, comme grep etc., mais au lieu d'être contenu dans un fichier séparé, il s'agit de intégré dans bash lui-même . Cela leur permet d'être plus efficaces que les commandes externes.

A mot-clé est également "codé en dur dans Bash, mais contrairement à un builtin, un mot-clé n'est pas en soi une commande, mais une sous-unité d'une construction de commande". J'interprète cela pour dire que les mots-clés n'ont aucune fonction seuls, mais nécessitent des commandes pour faire quoi que ce soit. (D'après le lien, d'autres exemples sont for , while , do et ! et il y en a d'autres dans ma réponse à votre autre question).

1voto

Sergiy Kolodyazhnyy Points 97292

Le manuel de la ligne de commande fourni avec Ubuntu ne donne pas de définition des mots-clés, mais la commande manuel en ligne (voir note de bas de page) et Spécifications standard du langage de commande POSIX Shell. Les deux standards POSIX, font référence à ces mots en tant que "mots réservés", et les deux fournissent des listes de ceux-ci. De la norme POSIX :

Cette reconnaissance ne se produit que lorsqu'aucun des caractères n'est cité et lorsque le mot est utilisé comme :

  • Le premier mot d'une commande

  • Le premier mot qui suit l'un des mots réservés autres que cas, pour, ou dans

  • Le troisième mot dans une commande de cas (seul in est valable dans ce cas)

  • Le troisième mot d'une commande for (seuls in et do sont valables dans ce cas)

La clé ici est que les mots-clés/mots réservés ont une signification spéciale parce qu'ils facilitent la syntaxe Shell, servent à signaler certains blocs de code tels que les boucles, les commandes composées, les instructions de branchement ( if/case ), etc. Ils permettent de former des instructions de commande, mais en eux-mêmes - ne font rien, et en fait si vous entrez des mots-clés tels que for , until , case - le Shell attendra une déclaration complète, sinon - erreur de syntaxe :

$ for
bash: syntax error near unexpected token `newline'
$  

Au niveau du code source, les mots réservés pour bash sont définis en parese.y tandis que les encastrés ont tout le répertoire qui leur sont consacrés.

Sidenote

L'index GNU montre [ comme un mot réservé, mais c'est en fait une commande intégrée. [[ par contre est un mot réservé.

Voir aussi : Différences entre mot-clé, mot réservé et buildin ?

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X