Env o no env

32

¿Cuál es la diferencia entre el comando

$ env FOO=bar baz

y

$ FOO=bar baz

¿Qué efecto envtiene?

August Karlstrom
fuente
44
Una especie de pregunta secundaria, pero ¿cómo se llama la característica en sí cuando configura una variable de entorno para un solo subcomando como ese? Siempre me ha costado encontrar información sobre esto porque no sé cómo se llama.
John Cromartie
1
@ JohnCromartie, deberías hacer eso como una pregunta.
cjm
1
Para bash, está documentado aquí: gnu.org/software/bash/manual/…
glenn jackman
2
@ JohnCromartie Es un componente opcional de cada comando de shell, por lo que se encuentra en la sección "Comandos simples" de la mayoría de los manuales de shell. Para POSIX, eso estaría aquí . Glenn ya te ha vinculado la sección análoga del manual de bash.
jw013
Establecer una variable que no existe a través de una asignación crea una variable de shell. Configurarlo a través de ENV o exportar la variable empuja la variable al entorno de ejecución del shell. Cambiar el valor de una variable existente actualizará el valor del entorno de ejecución si existe, de lo contrario, cámbielo en las variables internas del shell.
Johan

Respuestas:

26

Son funcionalmente equivalentes.

La principal diferencia es que env FOO=bar bazimplica invocar un proceso intermedio entre el shell y baz, donde al igual que con FOO=bar bazel shell, invoca directamente baz.
Por lo tanto, en ese sentido, FOO=bar bazse prefiere.

Las únicas situaciones en las que me encuentro usando env FOO=bares donde tengo que pasar un comando a otro comando.
Como ejemplo específico, digamos que tengo un script de contenedor que realiza algunas modificaciones del entorno y luego invoca execel comando que se le pasó, como:

#!/bin/bash
FOO=bob
some stuff
exec "$@"

Si lo ejecutas como myscript FOO=bar baz , execarrojará un error como exec FOO=bar bazno válido.
En cambio, lo llama como myscript env FOO=bar bazque se ejecuta como exec env FOO=bar baz, y es perfectamente válido.

Patricio
fuente
1
Sin FOO=bar exec bazembargo, puede hacerlo , por lo que no necesita enven su último punto.
Stéphane Chazelas
Cuando execalgo, ¿utiliza su entorno actual?
Glenn Jackman
1
Lo mismo ocurre con @StephaneChazelas, y también puede sudo FOO=bar bazpasar variables de entorno sin necesidad de hacerlo env.
Mike Miller
1
@StephaneChazelas que solo funciona si quiero incluir FOO=barel script. Si FOOno es siempre bar, no quiero a codificar ella, y en su lugar lo paso en.
Patrick
@glennjackman sí, siempre y cuando las variables se exporten o se pasen antes del exec, como FOO=bar exec baz.
Patrick
14

En este ejemplo en particular, no existe una diferencia efectiva, suponiendo que su shell es un shell compatible con POSIX, y suponiendo que bazes un ejecutable y no un shell incorporado.

Si su shell no es compatible con POSIX, por ejemplo , csho tcshla sintaxis

FOO=bar baz

no funciona y no hay una sintaxis de shell equivalente. Para esas conchas, elenv comando es la única forma de anular o inyectar variables de entorno para un solo comando.

Si bazes un shell integrado, digamos, fcpor ejemplo, envno dará los mismos resultados, porque envestá ejecutando un nuevo proceso en lugar de ser ejecutado directamente por el shell del comando. Además, no hay un fcejecutable, solo puede ejecutarse como un shell integrado debido a la forma en que interactúa con el entorno del shell, y también lo envhará nunca funcionará con un tipo incorporado fc.

Además, envofrece la -iopción, que le permite iniciar un comando en un entorno vacío con solo un conjunto específico de variables de entorno. Por envlo tanto, puede ser muy útil para iniciar procesos en entornos desinfectados, por ejemplo

env -i HOME=/tmp/homedir "PATH=`getconf PATH`" "TERM=$TERM" FOO=bar baz
Mike Miller
fuente
Cuando solía usar tcsh, escribía (setenv FOO bar; baz)para obtener la función equivalente.
Barmar
6

Además de lo que ya se ha dicho

VAR=value cmd args > redirs

Al ser una función de shell (Bourne / POSIX), está limitado en el nombre de las variables de entorno a las que pasa cmd. Deben ser nombres de variables de shell válidos y no deben ser de solo lectura o variables especiales para el shell.

Por ejemplo, no puedes hacer:

1=foo cmd

O

+++=bar cmd

bash no te permite hacer:

SHELLOPTS=xtrace cmd

Si bien puedes hacer:

env 1=foo cmd
env +++=bar cmd
env '=baz' cmd

(no es que quieras o debas querer hacer eso). O:

env SHELLOPTS=xtrace cmd

(A veces necesito hacer eso).

Tenga en cuenta que con envusted todavía no puede pasar una cadena de variable de entorno que no contenga un =(no es que tampoco quiera hacerlo).

Stéphane Chazelas
fuente
2

Un uso de enves permitir la $PATHbúsqueda de ejecutables en líneas shebang (porque envconsidera $PATHcuando busca el ejecutable). Esto es útil si el ejecutable que desea invocar puede estar en diferentes lugares en diferentes máquinas. Por ejemplo,

#!/usr/bin/env perl

en la primera línea de un script con conjunto de bits ejecutable ejecutará este script con Perl sin importar si está instalado en /usr/bin/perlo en/usr/local/bin/perl o en un lugar completamente diferente, siempre que el directorio esté en la ruta.

Por supuesto, esa búsqueda de ruta conlleva un riesgo adicional, pero el riesgo no es mayor que si hubiera escrito explícitamente perl yourscript.pl, lo que también busca perl en la ruta de búsqueda.

celtschk
fuente
2

Otro momento en el que enves realmente útil es si desea controlar el entorno por completo. Ejecuto un programa de servidor (Informix, en caso de que no pueda adivinar) cuyo entorno quiero controlar por completo. Lo ejecuto usando enval final de un script que establece un montón de variables con los valores correctos:

env -i HOME="$IXD" \
       INFORMIXDIR="$IXD" \
       INFORMIXSERVER="$IXS" \
       ${IXC:+INFORMIXCONCSMCFG="$IXC"} \
       ${IXH:+INFORMIXSQLHOSTS="$IXH"} \
       IFX_LISTEN_TIMEOUT=3 \
       ONCONFIG="onconfig.$IXS" \
       PATH="/bin:/usr/bin:$IXD/bin" \
       SHELL=/bin/ksh \
       TZ=UTC0 \
    $ONINIT "$@"

La -iopción elimina el entorno existente. Las VAR=valueopciones posteriores establecen las variables de entorno que quiero establecer; el nombre del programa está en $ONINIT, y cualquier argumento de línea de comando se pasa literalmente con "$@".

La ${IXH:+INFORMIXSQLHOSTS="$IXH"}construcción solo pasa INFORMIXSQLHOSTS="$IXH"a envsi $IXHse establece en un valor no vacío.

Jonathan Leffler
fuente