Je viens de rencontrer plusieurs réponses, telles que l' analyse d'un fichier texte délimité ... qui utilise la construction:
while IFS=, read xx yy zz;do
echo $xx $yy $zz
done < input_file
où la IFS
variable est définie avant la read
commande.
J'ai lu la référence bash mais je ne peux pas comprendre pourquoi c'est légal.
j'ai essayé
$ x="once upon" y="a time" echo $x $y
à partir de l'invite de commande bash mais rien ne se fait écho. Quelqu'un peut-il m'indiquer où cette syntaxe est définie dans la référence qui permet à la variable IFS d'être définie de cette manière? Est-ce un cas particulier ou puis-je faire quelque chose de similaire avec d'autres variables?
bash
shell
environment-variables
Mike Lippert
la source
la source
Réponses:
C'est sous Shell Grammar, Simple Commands (emphase ajoutée):
Ainsi, vous pouvez passer n'importe quelle variable de votre choix. Votre
echo
exemple ne fonctionne pas car les variables sont transmises à la commande et ne sont pas définies dans le shell. Le shell se développe$x
et$y
avant d' appeler la commande. Cela fonctionne, par exemple:la source
man bash
sur mon système ...Les variables définies deviennent des variables d’environnement sur le processus forké.
Si tu cours
puis bash se développe d'abord
$A
dans""
puis s'exécuteVoici le bon chemin:
Notez les guillemets simples dans
bash -c
, sinon vous avez le même problème que ci-dessus.Ainsi, votre exemple de boucle est légal car la commande 'read' intégrée dans bash va rechercher IFS dans ses variables d’environnement et trouver
,
. Donc,imprimera
TEST is and I is test
Enfin, comme pour la syntaxe, une chaîne est attendue dans une boucle for. Par conséquent, je devais utiliser des backticks pour en faire une commande. Cependant, les boucles while attendent une syntaxe de commande, telle que
IFS=, read xx yy zz
.la source
A
variable non définie , bash se développe$A
en une chaîne vide, mais pour éviter toute confusion, je ne l’utiliserais pas""
car le code n’est pas équivalent àA="b" echo ""
. Il n'y aura aucun argument àecho
.man bash
Les variables sont développées avant que l'affectation de variable ait lieu. Pour la raison évidente, cela
var=x
fonctionnerait dans l'autre sens également, maisvar=$othervar
ne le ferait pas. C'est-à-dire que votre$x
est nécessaire avant qu'il ne soit disponible. Mais ce n'est pas le problème principal. Le principal problème est que la ligne de commande ne peut être modifiée que par l'environnement shell mais que l'affectation ne fait pas partie de l'environnement shell.Vous mélangez les fonctionnalités: vous souhaitez remplacer la ligne de commande mais placez la définition de la variable dans l'environnement des commandes. Les remplacements de ligne de commande doivent être effectués par le shell. L'environnement doit être explicitement utilisé par la commande appelée. Si et comment cela est fait dépend de la commande.
L'avantage de cette utilisation est que vous pouvez définir l'environnement pour un sous-processus sans affecter l'environnement shell.
fonctionne comme prévu car, dans ce cas, les deux fonctions sont combinées: Le remplacement de la ligne de commande n’est pas effectué par le shell appelant, mais par le shell du sous-processus.
la source
x="once upon" y="a time" eval 'echo $x $y'
lorsqu'il n'y a pas de sous-processus impliqué, car ileval
s'agit d'un processus intégré. Je suppose que la citation pertinente de la page de manuel estThe environment for any simple command or function may be augmented temporarily by prefixing it with parameter assignments
. Considérant l’exemple de la question, il doit en être ainsi puisqueread
c’est aussi un processus intégré qui fonctionne avec un état de changement temporelIFS
.La commande que vous fournissez est différente car
$x
et$y
est développée avant l'echo
exécution de la commande. Par conséquent, leurs valeurs dans le shell actuel sont utilisées et non les valeurs quiecho
seraient affichées dans son environnement si elles devaient être examinées.la source
x
ety
destinées à l'environnement quiecho
s'exécute, pas à l'environnement dans lequel les argumentsecho
sont développés. CarIFS=, read xx yy zz
toute la chaîne est lue, non coupée, par laread
commande. Ensuite , cette chaîne de caractères est divisée en fonction de la valeur deIFS
, avec les pièces correspondantes attribuées àxx
,yy
etzz
.bash
commence par analyser la ligne de commande donnée, reconnaît qu'il y a deux affectations de variable à appliquer à l'environnement de la commande à venir, identifie la commande à exécuter (echo
), développe tous les paramètres trouvés dans les arguments, puis exécute la commandeecho
avec les arguments développés.echo
je n'étais pas sûr s'il pouvait "voir" la variable, car il s'agit d'une commande intégrée et ne s'exécute donc pas dans un sous-shell pouvant avoir son propre environnement. Mais je l'ai essayé aveceval
qui est aussi un construit et il le sait en effet. Par exemple, essayez lesa=xyz eval 'echo $BASHPID $a; grep -z ^a /proc/$BASHPID/{,task/*}/environ'; echo $BASHPID $a
émissions quia
ne sont définies que dans,eval
même si le pid est identique et que l'environnement n'est pas modifié pendant eval! (Pour pouvoir y accéder,/proc
vous devez exécuter ceci sous Linux.) Il semble que bash fasse de la magie supplémentaire ici.Je vais pour la plus grande image de " pourquoi c'est légal"
Réponse: Pour que vous puissiez appeler ou appeler un programme et pour cette invocation, utilisez uniquement une variable avec une variable particulière.
Par exemple: vous avez un paramètre pour une connexion à une base de données appelé "db_connection", et vous transmettez normalement "test" comme nom de votre connexion à la base de données test. En fait, vous pouvez même le définir comme paramètre par défaut que vous n'avez pas besoin de transmettre explicitement. Parfois, cependant, vous voulez travailler avec la base de données ci. Ainsi, vous transmettez le paramètre en tant que "ci", puis le programme appelé utilise ce paramètre de base de données comme nom de la base de données à utiliser pour tous les appels de base de données. Pour la prochaine exécution, si vous ne répétez pas l'approche et appelez simplement le programme, la variable reviendra à sa valeur par défaut précédente.
la source
Vous pouvez également utiliser
;
. Il sera évalué auparavant car c'est un séparateur de commandes.la source