¿Cómo configuro una variable de entorno en la línea de comando y hago que aparezca en los comandos?

Respuestas:

180

Esto se debe a que el shell expande la variable en la línea de comando antes de que realmente ejecute el comando y en ese momento la variable no existe. Si utiliza

TEST=foo; echo $TEST

funcionará.

exporthará que la variable aparezca en el entorno de los comandos ejecutados posteriormente (para ver cómo funciona esto en bash see help export). Si solo necesita que la variable aparezca en el entorno de un comando, use lo que ha intentado, es decir:

TEST=foo your-application
Peterph
fuente
1
¿Qué pasa con / usr / bin / env? eso tampoco funciona, ¿sabes por qué?
Benubird
55
La misma razón: el shell se expande $TESTantes de que se ejecute la línea de comando. Una vez que se echoestá ejecutando (también tenga en cuenta que echogeneralmente se traducirá en el comando incorporado del shell y no en /bin/echo), ve la variable establecida en su entorno. Sin embargo, echo $TESTno le indica echoa la salida el contenido de la variable TESTde su entorno. Le dice al shell que se ejecute echocon el argumento que sea lo que sea actualmente en la variable llamada TEST, y esas son dos cosas muy diferentes.
peterph
@peterph Si shell expande la variable en la línea de comando antes de que realmente ejecute el comando, ¿por qué no lo expande var=value sh -c 'echo "$var"'?
piratea el
Como te expliqué aquí : es porque las variables se expanden dentro de comillas dobles (por ejemplo, "… $var …") pero no dentro de comillas simples (por ejemplo, '… $var …'). Como echo "$var"está dentro de comillas simples, toda la cadena se pasa al nuevo sh -cshell ( ) sin ser interpretada por el shell externo e interactivo. … (Continúa)
G-Man
(Continúa) ... Como dijo ayer Igal , hay dos rondas de análisis, aunque creo que igal leyó mal su pregunta. No hay dos rondas de análisis aparte del análisis que realiza el shell principal. Hay dos rondas de análisis: una realizada por el shell externo, interactivo (padre) y otra por el nuevo sh -cshell hijo ( ).
G-Man
39

Sospecho que desea tener variables de shell para tener un alcance limitado, en lugar de variables de entorno. Las variables de entorno son una lista de cadenas que se pasan a los comandos cuando se ejecutan .

En

var=value echo whatever

Estás pasando la var=valuecadena al entorno que recibe echo. Sin embargo, echono hace nada con su lista de entornos y, de todos modos, en la mayoría de los shells, echoestá integrado y, por lo tanto, no se ejecuta .

Si hubieras escrito

var=value sh -c 'echo "$var"'

Eso hubiera sido otro asunto. Aquí, pasamos var=valueal shcomando y shutilizamos su entorno. Los shells convierten cada una de las variables que reciben de su entorno en una variable de shell, por lo que la varvariable de entorno que shrecibe se convertirá en una $varvariable, y cuando se expanda en esa echolínea de comando, se convertirá echo value. Debido a que el entorno se hereda por defecto, echotambién recibirá var=valueen su entorno (o lo haría si se ejecutara), pero nuevamente, echono le importa el entorno.

Ahora, si sospecho que lo que quiere es limitar el alcance de las variables de shell, hay varios enfoques posibles.

Portablemente (Bourne y POSIX):

(var=value; echo "1: $var"); echo "2: $var"

El (...) anterior inicia un sub-shell (un nuevo proceso de shell en la mayoría de los shells), por lo que cualquier variable declarada allí solo afectará a ese sub-shell, por lo que esperaría que el código anterior arroje "1: valor" y "2:" o "2: whatever-var-was-set-to-before".

Con la mayoría de los shells tipo Bourne, puede usar funciones y el "local" incorporado:

f() {
  local var
  var=value
  echo "1: $var"
}
f
echo "2: $var"

Con zsh, puede usar funciones en línea:

(){ local var=value; echo "1: $var"; }; echo "2: $var"

o:

function { local var=value; echo "1: $var"; }; echo "2: $var"

Con bash y zsh (pero no ash, pdksh o AT&T ksh), este truco también funciona:

var=value eval 'echo "1: $var"'; echo "2: $var"

Una variante que funciona en unos pocos más conchas ( dash, mksh, yash) pero no zsh(a menos que en el sh/ kshla emulación):

var=value command eval 'echo "1: $var"'; echo "2: $var"

(el uso commanden frente de un builtin especial (aquí eval) en los shells POSIX elimina su especialidad (aquí las asignaciones de variables de ellos permanecen vigentes después de que han regresado)

Stéphane Chazelas
fuente
Para mis propósitos, esta es la solución correcta. No quiero que la variable 'var' contamine el medio ambiente como lo hace en la respuesta aceptada.
kronenpj
6

Lo estás haciendo correctamente, pero la sintaxis de bash es fácil de malinterpretar: podrías pensar que eso echo $TESThace echoque TESTenv env env y luego lo imprima, no lo hace. Así dado

export TEST=123

entonces

TEST=456 echo $TEST

implica la siguiente secuencia:

  1. El shell analiza la línea de comando completa y ejecuta todas las sustituciones variables, por lo que la línea de comando se convierte en

    TEST=456 echo 123
  2. Crea los valores temporales establecidos antes del comando, por lo que guarda el valor actual TESTy lo sobrescribe con 456; la línea de comando es ahora

    echo 123
  3. Ejecuta el comando restante, que en este caso imprime 123 en stdout (por lo que el comando de shell que queda ni siquiera usó el valor temporal de TEST)

  4. Restaura el valor de TEST

Utilice printenv en su lugar, ya que no implica la sustitución de variables:

>> export TEST=123
>> printenv TEST
123
>> TEST=456 printenv TEST
456
>> printenv TEST && TEST=456 printenv TEST && TEST=789 printenv TEST && printenv TEST
123
456
789
123
>>
Oliver
fuente
+1 Me pareció printenvútil para probar / probar el concepto (se comporta como lo hace un script, en lugar de echo)
Daryn
5

Puede hacer que esto funcione usando:

TEST=foo && echo $TEST
Pradeepchhetri
fuente
66
En este caso, TEST=foose ejecuta como una declaración separada, no solo se establece en el contexto de echo.
codeforester