web-dev-qa-db-fra.com

Définition d'une variable d'environnement avant qu'une commande dans bash ne fonctionne pas pour la deuxième commande dans un tube

Dans un Shell donné, normalement, je définissais une ou plusieurs variables, puis 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 modifiez une variable LC_ * (ce qui semble affecter la commande, mais PAS ses arguments, par exemple les plages de caractères '[a-z]') ou lorsque vous redirigez la sortie vers une autre commande comme suit:

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

Je peux préfixer certaines commandes2 avec "FOO = barre" également, ce qui fonctionne mais ajoute une duplication non désirée, et cela n'aide en rien les arguments interprétés en fonction de la variable (par exemple '[a-z]')

Alors, quel est le bon 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

Edit: j'ai beaucoup de bonnes réponses! Le but est de garder cela un one-liner, de préférence sans utiliser "export". La méthode utilisant un appel à bash était globalement la meilleure solution, bien que la version entre parenthèses avec "export" soit un peu plus compacte. La méthode consistant à utiliser une redirection plutôt qu'un canal est également intéressante.

314
MartyMacGyver
FOO=bar bash -c 'somecommand someargs | somecommand2'
274

Pourquoi ne pas exporter la variable, mais uniquement à l'intérieur du sous-shell?:

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

Keith a un point, pour exécuter les commandes sans condition, procédez comme suit:

(export FOO=bar; somecommand someargs | somecommand2)
185
0xC0000022L

Vous pouvez également utiliser eval:

FOO=bar eval 'somecommand someargs | somecommand2'

Puisque cette réponse avec eval ne semble pas plaire à tout le monde, permettez-moi de clarifier une chose: lorsqu'elle est utilisée telle quelle, avec les guillemets simples, elle est parfaitement sûre. C’est bien, car il ne lancera pas de 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).

Au fur et à mesure que nous obtenons quelques points de vue réguliers, il est probablement bon de proposer une alternative à eval qui plaira à tout le monde et qui présente tous les avantages (et peut-être même plus!) De ce rapide eval "astuce". Il suffit d'utiliser une fonction! Définissez une fonction avec toutes vos commandes:

mypipe() {
    somecommand someargs | somecommand2
}

et exécutez-le avec vos variables d'environnement comme ceci:

FOO=bar mypipe
39
gniourf_gniourf

Utilisez env.

Par exemple, env FOO=BAR command. Notez que les variables d'environnement seront restaurées/inchangées à nouveau lorsque command sera terminé.

Méfiez-vous des substitutions de shell, par exemple si vous souhaitez référencer explicitement $FOO sur la même ligne de commande, vous devrez peut-être y échapper afin que votre interpréteur de shell n'effectue pas la substitution avant il tourne env.

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