bash - programas - shell script linux español
¿Puede un script de shell establecer variables de entorno del shell de llamada? (21)
Agregue la marca -l en la parte superior de su script de bash, es decir
#!/usr/bin/env bash -l
...
export NAME1="VALUE1"
export NAME2="VALUE2"
Los valores con NAME1
y NAME2
ahora se habrán exportado a su entorno actual, sin embargo, estos cambios no son permanentes. Si desea que sean permanentes, debe agregarlos a su archivo .bashrc
u otro archivo de inicio.
De las páginas del manual:
-l Make bash act as if it had been invoked as a login shell (see INVOCATION below).
Estoy tratando de escribir un script de shell que, cuando se ejecute, establecerá algunas variables de entorno que permanecerán establecidas en el shell del llamante.
setenv FOO foo
en csh / tcsh, o
export FOO=foo
in sh / bash solo lo configuro durante la ejecución del script.
eso ya lo se
source myscript
ejecutará los comandos de la secuencia de comandos en lugar de lanzar un nuevo shell, y eso puede resultar en configurar el entorno del "llamador".
Pero aquí está el problema:
Quiero que este script sea llamable desde bash o csh. En otras palabras, quiero que los usuarios de cualquiera de los shell puedan ejecutar mi script y que se cambie el entorno de su shell. Así que ''source'' no funcionará para mí, ya que un usuario que ejecuta csh no puede generar una secuencia de comandos bash, y un usuario que ejecuta bash no puede obtener una secuencia de comandos csh.
¿Hay alguna solución razonable que no implique tener que escribir y mantener DOS versiones en el script?
Aparte de los escritos, los condicionales dependen de lo que se establece en $ SHELL / $ TERM, no. ¿Qué hay de malo en usar Perl? Es bastante ubicuo (no puedo pensar en una sola variante de UNIX que no la tenga), y le ahorrará el problema.
Bajo OS X bash puedes hacer lo siguiente:
Crea el archivo de script bash para desarmar la variable
#!/bin/bash
unset http_proxy
Hacer el archivo ejecutable.
sudo chmod 744 unsetvar
Crear alias
alias unsetvar=''source /your/path/to/the/script/unsetvar''
Debería estar listo para usar siempre que tenga la carpeta que contiene su archivo de script adjunto a la ruta.
Creé una solución utilizando tuberías, eval y señal.
parent() {
if [ -z "$G_EVAL_FD" ]; then
die 1 "Rode primeiro parent_setup no processo pai"
fi
if [ $(ppid) = "$$" ]; then
"$@"
else
kill -SIGUSR1 $$
echo "$@">&$G_EVAL_FD
fi
}
parent_setup() {
G_EVAL_FD=99
tempfile=$(mktemp -u)
mkfifo "$tempfile"
eval "exec $G_EVAL_FD<>''$tempfile''"
rm -f "$tempfile"
trap "read CMD <&$G_EVAL_FD; eval /"/$CMD/"" USR1
}
parent_setup #on parent shell context
( A=1 ); echo $A # prints nothing
( parent A=1 ); echo $A # prints 1
Podría funcionar con cualquier comando.
Debería usar módulos, vea http://modules.sourceforge.net/
EDITAR: El paquete de módulos no se ha actualizado desde 2012 pero aún funciona bien para lo básico. Todas las nuevas funciones, campanas y silbidos suceden en lmod este día (lo cual me gusta más): https://www.tacc.utexas.edu/research-development/tacc-projects/lmod
En mi .bash_profile tengo:
# No Proxy
function noproxy
{
/usr/local/sbin/noproxy #turn off proxy server
unset http_proxy HTTP_PROXY https_proxy HTTPs_PROXY
}
# Proxy
function setproxy
{
sh /usr/local/sbin/proxyon #turn on proxy server
http_proxy=http://127.0.0.1:8118/
HTTP_PROXY=$http_proxy
https_proxy=$http_proxy
HTTPS_PROXY=$https_proxy
export http_proxy https_proxy HTTP_PROXY HTTPS_PROXY
}
Entonces, cuando quiero deshabilitar el proxy, las funciones se ejecutan en el shell de inicio de sesión y establecen las variables según lo esperado y deseado.
Es "posible" mediante el uso de gdb y setenv(3) , aunque me cuesta mucho recomendar hacer esto. (Además, es decir, la ubuntu más reciente no le permitirá hacer esto sin decirle al kernel que sea más permisivo con respecto a ptrace, y lo mismo puede suceder con otras distribuciones también).
$ cat setfoo
#! /bin/bash
gdb /proc/${PPID}/exe ${PPID} <<END >/dev/null
call setenv("foo", "bar", 0)
END
$ echo $foo
$ ./setfoo
$ echo $foo
bar
Esto funciona, no es lo que yo usaría, pero ''funciona''. Vamos a crear un script para establecer la variable de entorno TEREDO_WORMS
:
#!/bin/ksh
export TEREDO_WORMS=ukelele
exec $SHELL -i
Será interpretado por el shell Korn, exporta la variable de entorno y luego se reemplaza a sí mismo con un nuevo shell interactivo.
Antes de ejecutar este script, hemos establecido SHELL
en el entorno al shell C, y la variable de entorno TEREDO_WORMS
no está configurada:
% env | grep SHELL
SHELL=/bin/csh
% env | grep TEREDO
%
Cuando se ejecuta el script, se encuentra en un shell nuevo, otro shell C interactivo, pero la variable de entorno se establece:
% teredo
% env | grep TEREDO
TEREDO_WORMS=ukelele
%
Al salir de este shell, el shell original toma el control:
% exit
% env | grep TEREDO
%
La variable de entorno no está configurada en el entorno del shell original. Si usa exec teredo
para ejecutar el comando, entonces el shell interactivo original es reemplazado por el shell Korn que establece el entorno, y luego ese es reemplazado por un nuevo shell C interactivo:
% exec teredo
% env | grep TEREDO
TEREDO_WORMS=ukelele
%
Si escribe exit
(o Control-D ), entonces su shell se cierra, probablemente desconectándose de esa ventana, o regresando al nivel anterior de shell desde donde comenzaron los experimentos.
El mismo mecanismo funciona para Bash o Korn shell. Es posible que el aviso después de los comandos de salida aparezca en lugares divertidos.
Tenga en cuenta la discusión en los comentarios. Esta no es una solución que recomendaría, pero logra el propósito declarado de un solo script para configurar el entorno que funciona con todos los shells (que aceptan la opción -i
para crear un shell interactivo). También puede agregar "$@"
después de la opción de retransmitir cualquier otro argumento, lo que luego podría hacer que el shell sea utilizable como una herramienta general ''establecer entorno y ejecutar comando''. Es posible que desee omitir el -i
si hay otros argumentos, lo que lleva a:
#!/bin/ksh
export TEREDO_WORMS=ukelele
exec $SHELL "${@-''-i''}"
El bit "${@-''-i''}"
significa'' si la lista de argumentos contiene al menos un argumento, use la lista de argumentos original; de lo contrario, sustituya -i
por los argumentos inexistentes ''.
Hice esto hace muchos años. Si me acuerdo correctamente, incluí un alias en cada uno de .bashrc y .cshrc, con parámetros, alias las formas respectivas de configurar el entorno en una forma común.
Luego, el script que obtendrá en cualquiera de los dos shells tiene un comando con esa última forma, que es un alias adecuado para cada shell.
Si encuentro los alias concretos, los publicaré.
La respuesta corta es no, no puede alterar el entorno del proceso principal, pero parece que lo que desea es un entorno con variables de entorno personalizadas y el shell que el usuario ha elegido.
Entonces, ¿por qué no simplemente algo como
#!/usr/bin/env bash
FOO=foo $SHELL
Luego, cuando haya terminado con el medio ambiente, simplemente exit
.
No es lo que yo llamaría sobresaliente, pero esto también funciona si necesita llamar al script desde el shell de todos modos. No es una buena solución, pero para una sola variable de entorno estática, funciona lo suficientemente bien.
1.) Cree un script con una condición que salga de 0 (Correcto) o 1 (No exitoso)
if [[ $foo == "True" ]]; then
exit 0
else
exit 1
2.) Cree un alias que dependa del código de salida.
alias=''myscript.sh && export MyVariable''
Llama al alias, que llama al script, que evalúa la condición, que se requiere para salir de cero a través de ''&&'' para establecer la variable de entorno en el shell principal.
Se trata de restos flotantes, pero puede ser útil en caso de apuro.
No podrá modificar el shell de la persona que llama porque está en un contexto de proceso diferente. Cuando los procesos secundarios heredan las variables de su shell, ellos heredan las copias.
Una cosa que puedes hacer es escribir un script que emita los comandos correctos para tcsh o sh según cómo se invoque. Si tu script es "setit" entonces haz:
ln -s setit setit-sh
y
ln -s setit setit-csh
Ahora bien, directamente o en un alias, haces esto desde sh
eval `setit-sh`
o esto de csh
eval `setit-csh`
setit usa $ 0 para determinar su estilo de salida.
Esto es reminiscente de cómo se usa la gente para obtener el conjunto de variables de entorno TERM.
La ventaja aquí es que setit está escrito en cualquier shell que te guste como en:
#!/bin/bash
arg0=$0
arg0=${arg0##*/}
for nv in /
NAME1=VALUE1 /
NAME2=VALUE2
do
if [ x$arg0 = xsetit-sh ]; then
echo ''export ''$nv'' ;''
elif [ x$arg0 = xsetit-csh ]; then
echo ''setenv ''${nv%%=*}'' ''${nv##*=}'' ;''
fi
done
con los enlaces simbólicos dados anteriormente, y la evaluación de la expresión backquoted, esto tiene el resultado deseado.
Para simplificar la invocación de csh, tcsh o shells similares:
alias dosetit ''eval `setit-csh`''
o para sh, bash, y similares:
alias dosetit=''eval `setit-sh`''
Una cosa buena sobre esto es que solo tienes que mantener la lista en un solo lugar. En teoría, incluso podría pegar la lista en un archivo y colocar cat nvpairfilename
entre "in" y "do".
Esto es más o menos lo que solía hacer la configuración del terminal de shell de inicio de sesión: una secuencia de comandos generaría las instrucciones que se ejecutarán en el shell de inicio de sesión. Generalmente se usaría un alias para simplificar la invocación, como en "tset vt100". Como se mencionó en otra respuesta, también hay una funcionalidad similar en el servidor de noticias INN UseNet.
No veo ninguna respuesta que documente cómo solucionar este problema con procesos de cooperación. Un patrón común con cosas como ssh-agent
es hacer que el proceso hijo imprima una expresión que el padre puede eval
.
bash$ eval $(shh-agent)
Por ejemplo, ssh-agent
tiene opciones para seleccionar sintaxis de salida compatible con Csh o Bourne.
bash$ ssh-agent
SSH2_AUTH_SOCK=/tmp/ssh-era/ssh2-10690-agent; export SSH2_AUTH_SOCK;
SSH2_AGENT_PID=10691; export SSH2_AGENT_PID;
echo Agent pid 10691;
(Esto hace que el agente comience a ejecutarse, pero no le permite usarlo realmente, a menos que ahora copie y pegue esta salida en el indicador de comandos de su shell). Compare:
bash$ ssh-agent -c
setenv SSH2_AUTH_SOCK /tmp/ssh-era/ssh2-10751-agent;
setenv SSH2_AGENT_PID 10752;
echo Agent pid 10752;
(Como puede ver, csh
y tcsh
usan setenv
para establecer las variables).
Tu propio programa también puede hacer esto.
bash$ foo=$(makefoo)
Su script makefoo
simplemente calcularía e imprimiría el valor, y permitiría a la persona que llama hacer lo que quiera con él. Asignarlo a una variable es un caso de uso común, pero probablemente no sea algo que desee incluir en la herramienta que produce el código. valor.
Otra opción es usar "Módulos de entorno" ( http://modules.sourceforge.net/ ). Lamentablemente, esto introduce un tercer idioma en la mezcla. Usted define el entorno con el lenguaje de Tcl, pero hay algunos comandos prácticos para las modificaciones típicas (anteponer frente a añadir frente a conjunto). También necesitarás tener instalados módulos de entorno. Luego puede usar el module load *XXX*
para nombrar el entorno que desea. El comando del módulo es básicamente un alias elegante para el mecanismo de eval
descrito anteriormente por Thomas Kammeyer. La principal ventaja aquí es que puede mantener el entorno en un idioma y confiar en "Módulos de entorno" para traducirlo a sh, ksh, bash, csh, tcsh, zsh, python (?!? !!), etc.
Otra solución que no veo mencionada es escribir el valor de la variable en un archivo.
Me encontré con un problema muy similar en el que quería poder ejecutar la última prueba de configuración (en lugar de todas mis pruebas). Mi primer plan fue escribir un comando para configurar la variable env TESTCASE, y luego tener otro comando que usaría esto para ejecutar la prueba. No hace falta decir que tuve el mismo problema exacto que tú.
Pero luego se me ocurrió este simple truco:
Primer comando ( testset
):
#!/bin/bash
if [ $# -eq 1 ]
then
echo $1 > ~/.TESTCASE
echo "TESTCASE has been set to: $1"
else
echo "Come again?"
fi
Segundo comando ( testrun
):
#!/bin/bash
TESTCASE=$(cat ~/.TESTCASE)
drush test-run $TESTCASE
Puede indicar al proceso hijo que imprima sus variables de entorno (llamando a "env"), luego haga un bucle sobre las variables de entorno impresas en el proceso principal y llame a "exportar" sobre esas variables.
El siguiente código se basa en la captura de salida de encontrar. -print0 en una matriz de bash
Si el shell primario es el bash, puedes usar
while IFS= read -r -d $''/0'' line; do
export "$line"
done < <(bash -s <<< ''export VARNAME=something; env -0'')
echo $VARNAME
Si el shell primario es el guión, la read
no proporciona la marca -d y el código se complica
TMPDIR=$(mktemp -d)
mkfifo $TMPDIR/fifo
(bash -s << "EOF"
export VARNAME=something
while IFS= read -r -d $''/0'' line; do
echo $(printf ''%q'' "$line")
done < <(env -0)
EOF
) > $TMPDIR/fifo &
while read -r line; do export "$(eval echo $line)"; done < $TMPDIR/fifo
rm -r $TMPDIR
echo $VARNAME
Puedes invocar otro Bash con los diferentes bash_profile. Además, puede crear bash_profile especial para usar en un entorno multi-bashprofile.
Recuerde que puede usar funciones dentro de bashprofile, y que las funciones estarán disponibles de forma global. por ejemplo, "function user {export USER_NAME $ 1}" puede establecer una variable en tiempo de ejecución, por ejemplo: usuario olegchir && env | grep olegchir
Siempre se podrían usar alias.
alias your_env=''source ~/scripts/your_env.sh''
Su proceso de shell tiene una copia del entorno principal y no tiene acceso al entorno del proceso principal en absoluto. Cuando su proceso de shell termina, cualquier cambio que haya hecho en su entorno se perderá. La obtención de un archivo de script es el método más comúnmente utilizado para configurar un entorno de shell, es posible que solo desee morder la bala y mantener una para cada uno de los dos tipos de shell.
Técnicamente, eso es correcto, solo ''eval'' no bifurca otro shell. Sin embargo, desde el punto de vista de la aplicación que está intentando ejecutar en el entorno modificado, la diferencia es nula: el elemento secundario hereda el entorno de su principal, por lo que el entorno (modificado) se transmite a todos los procesos descendentes.
Ipso facto, la variable de entorno modificada se "pega", siempre y cuando se esté ejecutando bajo el programa / shell padre.
Si es absolutamente necesario que la variable de entorno permanezca después de que el padre (Perl o shell) haya salido, es necesario que el shell primario haga el trabajo pesado. Uno de los métodos que he visto en la documentación es que la secuencia de comandos actual genere un archivo ejecutable con el lenguaje de ''exportación'' necesario, y luego engañe a la shell primaria para que lo ejecute, siempre consciente del hecho de que necesita prefacio Comando con ''source'' si está intentando dejar atrás una versión no volátil del entorno modificado. Un Kluge en el mejor de los casos.
El segundo método es modificar la secuencia de comandos que inicia el entorno de shell (.bashrc o lo que sea) para que contenga el parámetro modificado. Esto puede ser peligroso: si aplica la secuencia de comandos de inicialización, es posible que su shell no esté disponible la próxima vez que intente iniciarse. Hay muchas herramientas para modificar el shell actual; al colocar los ajustes necesarios en el ''lanzador'', también puede impulsar esos cambios. Generalmente no es una buena idea; Si solo necesita los cambios de entorno para un conjunto de aplicaciones en particular, tendrá que regresar y devolver el script de inicio de shell a su estado original (usando vi o lo que sea) después.
En resumen, no hay métodos buenos (y fáciles). Presumiblemente, esto se hizo difícil para garantizar que la seguridad del sistema no se viera comprometida de manera irrevocable.
Utilice la "sintaxis de llamada" del espacio de puntos. Por ejemplo, aquí está cómo hacerlo usando la ruta completa a un script:
. /path/to/set_env_vars.sh
Y aquí está cómo hacerlo si está en el mismo directorio que el script:
. set_env_vars.sh
Estos ejecutan el script bajo el shell actual en lugar de cargar otro (que es lo que sucedería si lo ./set_env_vars.sh
). Debido a que se ejecuta en el mismo shell, las variables de entorno que establezca estarán disponibles cuando salga.
Esto es lo mismo que llamar a la source set_env_vars.sh
, pero es más corto de escribir y puede funcionar en algunos lugares donde la source
no lo hace.