L'idée de base est que les VAR=VALUE some-command
jeux VAR
à VALUE
l'exécution de some-command
quand some-command
est une commande externe, et il ne reçoit pas plus de fantaisie que cela. Si vous combinez cette intuition avec une certaine connaissance du fonctionnement d'un shell, vous devriez trouver la bonne réponse dans la plupart des cas. La référence POSIX est «Simple Commands» dans le chapitre «Shell Command Language» .
Si some-command
est une commande externe , VAR=VALUE some-command
équivaut à env VAR=VALUE some-command
. VAR
est exporté dans l'environnement de some-command
, et sa valeur (ou son absence) dans le shell ne change pas.
Si some-command
est une fonction , alors VAR=VALUE some-command
est équivalent à VAR=VALUE; some-command
, c'est- à -dire que l'affectation reste en place après le retour de la fonction et que la variable n'est pas exportée dans l'environnement. La raison en est liée à la conception du shell Bourne (et par la suite à la compatibilité descendante): il n'avait pas la possibilité de sauvegarder et de restaurer les valeurs des variables autour de l'exécution d'une fonction. Ne pas exporter la variable est logique car une fonction s'exécute dans le shell lui-même. Cependant, ksh (y compris ATT ksh93 et pdksh / mksh), bash et zsh implémentent le comportement le plus utile où VAR
est défini uniquement pendant l'exécution de la fonction (il est également exporté). Dans ksh , cela se fait si la fonction est définie avec la syntaxe kshfunction NAME …
, pas s'il est défini avec la syntaxe standard NAME ()
. En bash , cela se fait uniquement en mode bash, pas en mode POSIX (lorsqu'il est exécuté avec POSIXLY_CORRECT=1
). Dans zsh , cela se fait si l' posix_builtins
option n'est pas définie; cette option n'est pas définie par défaut mais est activée par emulate sh
ou emulate ksh
.
Si some-command
est une fonction intégrée, le comportement dépend du type de fonction intégrée. Les éditions spéciales se comportent comme des fonctions. Les fonctions intégrées spéciales sont celles qui doivent être implémentées à l'intérieur du shell car elles affectent le shell d'état (par exemple, break
affectent le flux de contrôle, cd
affectent le répertoire courant, set
affectent les paramètres et options de position…). D'autres fonctions intégrées sont intégrées uniquement pour des raisons de performances et de commodité (principalement - par exemple, la fonction bash printf -v
ne peut être implémentée que par une fonction intégrée), et elles se comportent comme une commande externe.
L'affectation a lieu après l'expansion de l'alias, donc s'il some-command
s'agit d'un alias , développez-le d'abord pour trouver ce qui se passe.
Notez que dans tous les cas, l'affectation est effectuée après l'analyse de la ligne de commande, y compris toute substitution de variable sur la ligne de commande elle-même. var=a; var=b echo $var
Imprime donc a
, car $var
est évalué avant que l'affectation n'ait lieu. Et IFS=. printf "%s\n" $var
utilise donc l'ancienne IFS
valeur pour se diviser $var
.
J'ai couvert tous les types de commandes, mais il y a un autre cas: quand il n'y a pas de commande à exécuter , c'est-à-dire si la commande se compose uniquement d'affectations (et éventuellement de redirections). Dans ce cas, l'affectation reste en place . VAR=VALUE OTHERVAR=OTHERVALUE
est équivalent à VAR=VALUE; OTHERVAR=OTHERVALUE
. Donc, après IFS=. arr=($var)
, IFS
reste réglé sur .
. Étant donné que vous pouvez utiliser $IFS
dans l'affectation à arr
en supposant qu'il a déjà sa nouvelle valeur, il est logique que la nouvelle valeur de IFS
soit utilisée pour l'expansion de $var
.
En résumé, vous pouvez utiliser uniquement IFS
pour le fractionnement temporaire de champs:
- en lançant un nouveau shell ou un sous-shell (par exemple,
third=$(IFS=.; set -f; set -- $var; echo "$3")
c'est une façon compliquée de faire third=${var#*.*.}
sauf qu'ils se comportent différemment lorsque la valeur de var
contient moins de deux .
caractères);
- en ksh,
IFS=. some-function
où some-function
est défini avec la syntaxe ksh function some-function …
;
- en bash et zsh, avec
IFS=. some-function
tant qu'ils fonctionnent en mode natif par opposition au mode de compatibilité.
IFS
reste réglé sur.
" Eek. Après avoir lu la première partie, cela a du sens, mais avant de poster ce Q, je ne m'y attendais pas.La réponse de @Gilles est vraiment formidable, explique-t-il (en détail) une question complexe.
Cependant, je crois que la réponse à la raison pour laquelle cette commande:
fonctionne comme il le fait est l'idée simple que toute la ligne de commande est analysée avant d' être exécutée. Et que chaque "mot" soit traité une fois par le shell.
Les affectations, comme
IFS=.
, sont retardées (l'étape 4 est la dernière):jusqu'à ce que la commande soit exécutée et que toutes les extensions des arguments soient traitées en premier pour créer cette ligne exécutable:
La valeur de
$var
est développée avec l '"ancien" IFSa.b.c
avant que la commandeprintf
ne reçoive les arguments"%s\n"
eta.b.c
.Eval
Un niveau de retard peut être introduit par
eval
:La ligne est analysée (1ère fois) et 'IFS =.' est défini sur l'environnement comme suit:
Ensuite, il est à nouveau analysé comme suit:
Et exécuté à ceci:
La valeur de
$var
(abc) est divisé par la valeur de l' IFS en cours d' utilisation:.
.Environnement
La partie complexe et délicate est ce qui est valable dans l'environnement quand !!!
Cela s'explique très bien dans la première partie de la réponse de Gilles.
Avec un détail supplémentaire.
Lorsque cette commande est exécutée:
La valeur d'IFS est conservée dans l'environnement actuel, oui:
IFS pour une seule instruction.
Mais cela pourrait être évité: définir IFS pour une seule instruction
la source
Votre question concernant
est un cas d'angle.
En effet, la
macro expansion
commande in se produit avant que la variable shell neIFS=.
soit définie.En d'autres termes: lorsque
$var
est développé, laIFS
valeur précédente est active, puisIFS
est définie sur'.'
.la source