563 votes

La définition d'une variable d'environnement avant une commande en Bash ne fonctionne pas pour la deuxième commande dans un pipe

Dans un shell donné, je dois normalement définir une ou plusieurs variables, puis exécuter une commande. Récemment, j'ai découvert le concept de l'ajout d'une définition de variable à une commande :

FOO=bar somecommand someargs

Cela fonctionne... en quelque sorte. Cela ne fonctionne pas lorsque vous changez une variable LC_* (ce qui semble affecter la commande, mais...). no ses arguments, par exemple, les plages de caractères '[a-z]') ou lorsqu'on envoie la sortie vers une autre commande de cette manière :

FOO=bar somecommand someargs | somecommand2  # somecommand2 is unaware of FOO

Je peux également faire précéder somecommand2 de "FOO=bar", ce qui fonctionne, mais ajoute une duplication indésirable, et n'aide pas avec les arguments qui sont interprétés en fonction de la variable (par exemple, '[a-z]').

Alors, quel est le meilleur moyen de faire cela sur une seule ligne ?

Je pense à quelque chose de l'ordre de :

FOO=bar (somecommand someargs | somecommand2)  # Doesn't actually work

J'ai eu beaucoup de bonnes réponses ! L'objectif est de faire en sorte que cela reste une ligne simple, de préférence sans utiliser "export". La méthode utilisant un appel à Bash était la meilleure dans l'ensemble, bien que la version entre parenthèses avec "export" était un peu plus compacte. La méthode consistant à utiliser une redirection plutôt qu'un pipe est également intéressante.

2 votes

(T=$(date) echo $T) fonctionnera

0 votes

Dans le cadre de scripts multiplateformes (y compris Windows) ou de projets basés sur npm (js ou autre), vous pouvez jeter un coup d'œil à l'outil de gestion de l'identité de l'utilisateur. module cross-env .

12 votes

J'espérais que l'une des réponses expliquerait aussi pourquoi cela ne fonctionne qu'en quelque sorte, c'est-à-dire que ce n'est pas équivalent à l'exportation de la variable avant l'appel.

477voto

Dennis Williamson Points 105818
FOO=bar bash -c 'somecommand someargs | somecommand2'

3 votes

Cela répond à mes critères (une seule ligne sans avoir besoin d'"exporter")... Je suppose qu'il n'y a pas de moyen de faire ceci sans en appelant "bash -c" (par exemple, l'utilisation créative des parenthèses) ?

2 votes

@MartyMacGyver : Aucun que je puisse penser. Cela ne fonctionnera pas non plus avec des accolades.

8 votes

Notez que si vous devez exécuter votre somecommand en tant que sudo, vous devez passer à sudo l'option -E pour faire passer des variables. Parce que les variables peuvent introduire des vulnérabilités. stackoverflow.com/a/8633575/1695680

325voto

0xC0000022L Points 9130

Comment exporter la variable, mais seulement à l'intérieur du sous-shell ?

(export FOO=bar && somecommand someargs | somecommand2)

Keith a raison, pour exécuter inconditionnellement les commandes, faites ceci :

(export FOO=bar; somecommand someargs | somecommand2)

0 votes

Cela semble fonctionner, bien que ce ne soit pas tout à fait ce que je recherchais (il se peut qu'il n'y ait aucun moyen de faire ce que je décris ci-dessus en une seule commande sans utiliser explicitement export d'abord...). Qu'en pensez-vous ?

21 votes

J'utiliserais ; plutôt que && ; il n'y a aucun moyen export FOO=bar va échouer.

0 votes

@Keith - Je me suis toujours posé la question de la différence entre && et ; (comme la plupart des questions sans mot, ce n'est pas vraiment facile à rechercher...). Je sais que Windows supporte && mais évidemment rien comme " ;", FWIW). Je pourrais me retrouver à utiliser soit cette construction, soit la construction bash, en fonction de l'audience.

78voto

benjimin Points 591

Utilice env .

Par exemple, env FOO=BAR command . Notez que les variables d'environnement seront à nouveau restaurées/changées lorsque command finit de s'exécuter.

Faites juste attention aux substitutions de l'interpréteur de commandes, c'est-à-dire que si vous voulez faire référence à $FOO explicitement sur la même ligne de commande, vous devrez peut-être l'échapper pour que votre interpréteur de shell n'effectue pas la substitution avant il fonctionne env .

$ export FOO=BAR
$ env FOO=FUBAR bash -c 'echo $FOO'
FUBAR
$ echo $FOO
BAR

62voto

gniourf_gniourf Points 9393

Vous pouvez également utiliser eval :

FOO=bar eval 'somecommand someargs | somecommand2'

Puisque cette réponse avec eval ne semble pas plaire à tout le monde, laissez-moi clarifier quelque chose : lorsqu'il est utilisé tel qu'il est écrit, avec les guillemets simples il est parfaitement sûr. Il est bon car il ne lancera pas un processus externe (comme la réponse acceptée) et n'exécutera pas les commandes dans un sous-shell supplémentaire (comme l'autre réponse).

Comme nous avons quelques vues régulières, il est probablement bon de donner une alternative à eval qui plaira à tout le monde, et qui présente tous les avantages (et peut-être même plus !) de ce système rapide. eval "truc". Il suffit d'utiliser une fonction ! Définissez une fonction avec toutes vos commandes :

mypipe() {
    somecommand someargs | somecommand2
}

et l'exécuter avec vos variables d'environnement comme ceci :

FOO=bar mypipe

26voto

Akhil Jalagam Points 1

Une approche simple consiste à utiliser ;

Par exemple :

ENV=prod; ansible-playbook -i inventories/$ENV --extra-vars "env=$ENV"  deauthorize_users.yml --check

command1; command2 exécute la commande 2 après l'exécution de la commande 1, de manière séquentielle. Il importe peu que les commandes aient réussi ou non.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X