Desarmar una variable de entorno para un comando

24

Puedo correr ENV_VAR=value commandpara correr commandcon un valor específico para ENV_VAR. ¿Cuál es el equivalente a desarmar ENV_VARpara command?

Alexey Romanov
fuente
77
Aparte: commandes una elección desafortunada de marcadores de posición, ya que en realidad hay un comando incorporado con ese nombre. mycommando somecommandtal vez sea un mejor hábito para entrar.
Charles Duffy
@CharlesDuffy, generalmente lo uso cmdpara eso.
Stéphane Chazelas

Respuestas:

35

Aparte de la -iopción, que borra todo el entorno, POSIX envno proporciona ninguna forma de desarmar una variable.

Sin embargo, con algunas envimplementaciones (incluidas GNU, busybox'y FreeBSD al menos), puede hacer:

env -u ENV_VAR command

Lo que funcionaría para eliminar cada instancia de una ENV_VARvariable del entorno (tenga en cuenta que no funciona para la variable de entorno con un nombre vacío ( env -u ''da un error o es ineficaz dependiendo de la implementación, aunque todos aceptan)env '=value' , probablemente una limitación) incurrido por la unsetenv()función C que POSIX requiere para devolver un error para la cadena vacía, mientras que no existe tal limitación para putenv())).

Portablemente (en shells POSIX), puede hacer:

(unset -v ENV_VAR; exec command)

(tenga en cuenta que con algunos shells, el uso execpuede cambiar quécommand se ejecuta: ejecuta el que está en el sistema de archivos en lugar de una función o incorporado, por ejemplo (y omitiría la aliasexpansión, obviamente), como envarriba. Desearía omitirlo en esos casos) .

Pero eso no funcionará para las variables de entorno que tienen un nombre que no se puede asignar a una variable de shell (tenga en cuenta que algunos shells como mksh eliminarían esas variables del entorno en el inicio de todos modos), o variables que se han marcado como de solo lectura.

-ves para el shell Bourne y bashcuyo unsetsin -vpodría desarmar una ENV_VAR función si no hubiera variable con ese nombre. La mayoría de los otros shells no desarmarían las funciones a menos que pases la -fopción. (Es poco probable que haga una diferencia en la práctica).

(También tenga cuidado con el error / mal funcionamiento de bash/ mksh/ yashcuyo unset, bajo ciertas circunstancias, no puede desarmar la variable, pero revela la variable en un ámbito externo )

Si perlestá disponible, puede hacer:

perl -e 'delete $ENV{shift@ARGV}; exec @ARGV or die$!' ENV_VAR command

Lo que funcionará incluso para la variable de entorno con un nombre vacío.

Ahora, todo eso no funcionará si desea cambiar una variable de entorno para una función o función incorporada y no desea que se ejecuten en una subshell, como en bash:

env -u LANG printf -v var %.3f 1.2 # would run /usr/bin/printf instead
(unset -v LANG; printf -v var %.3f 1.2) # changes to $var lost afterwards

(aquí, desarmar LANG como un enfoque equivocado para asegurarse de que .se usa y se entiende como el separador decimal. Sería mejor usarLC_ALL=C printf... para eso)

Con algunos shells, puede crear un ámbito local para la variable usando una función:

without() {
  local "$1" # $1 variable declared as initially unset in bash¹
  shift
  "$@"
}
without LANG printf -v var %.3f 1.2

Con zsh, también puede usar una función anónima:

(){local ENV_VAR; command}

Ese enfoque no funcionará en algunos shells (como los basados ​​en el shell Almquist), localque no declaran la variable como inicialmente no establecida (pero heredan el valor y los atributos). En esos, puede hacerlo local ENV_VAR; unset ENV_VAR, pero no lo haga en mksho yash(en typesetlugar de hacerlo local) ya que eso no funcionaría, unsetsolo estaría cancelando el local.

¹ También tenga en cuenta que en bashel local ENV_VAR(aunque no esté configurado) retendría el atributo de exportación . Entonces, si commandse tratara de una función que asigna un valor ENV_VAR, la variable estaría disponible en el entorno de los comandos llamados posteriormente. unset ENV_VARborraría ese atributo. O puede usar el local +x ENV_VARque también garantizaría una pizarra limpia (a menos que esa variable se haya declarado de solo lectura, pero no hay nada que pueda hacer al respecto bash).

Stéphane Chazelas
fuente
1
Es una pregunta separada, pero ¿qué diablos es una variable de entorno con un nombre vacío y cómo lo usaría alguna vez, incluso para algún tipo de explotación? ¿No tendría que escribir un programa que lea el entorno y busque específicamente algo como esto?
Joe
@ Joe, prueba por ejemplo env '=foo' python -c 'import os; print os.environ[""]'. No espero que muchas personas quieran establecer una variable como esa.
Stéphane Chazelas
9

No hay equivalente directo hasta donde yo sé; puedes usar una subshell:

(unset ENV_VAR; exec command)
Stephen Kitt
fuente
(unset ENV_VAR; exec somecommand)si quiere ser equivalente al original en eficiencia (consumiendo la subshell). Tal como está, esto agrega un tenedor adicional.
Charles Duffy el
1
@Charles, de hecho, aunque algunos shells lo hacen automáticamente ya que commandes el último comando en la invocación de subshell.
Stephen Kitt el
+1 porque esta forma es fácil de escribir para uso interactivo. Utilizo subshells para cambios únicos en el entorno de shell para un one-liner en lugar de recordar que es así env -u.
Peter Cordes
0

Puedes usar ENV_VAR= command

En realidad, esto no desarma la variable, pero puede ser útil en muchos casos (los scripts de shell generalmente solo se usan test -npara verificar si una variable está configurada):

$ export ENV_VAR=foo
$ mycommand
ENV_VAR: foo
$ ENV_VAR=bar mycommand
ENV_VAR: bar
$ ENV_VAR= mycommand
ENV_VAR: 
GnP
fuente