¿Cuál es la diferencia entre ejecutar un script Bash y obtenerlo?

Respuestas:

346

Respuesta corta

Obtener un script ejecutará los comandos en el proceso de shell actual .

La ejecución de un script ejecutará los comandos en un nuevo proceso de shell.

Utilice la fuente si desea que el script cambie el entorno en su shell actualmente en ejecución. use ejecutar de otra manera.

Si todavía estás confundido, sigue leyendo.

Terminología

Para aclarar alguna confusión común sobre la sintaxis a ejecutar y la sintaxis a la fuente:

./myscript

Esto se ejecutará myscript siempre que el archivo sea ejecutable y esté ubicado en el directorio actual. El punto inicial y la barra inclinada ( ./) denotan el directorio actual. Esto es necesario porque el directorio actual generalmente no está (y generalmente no debería estar) en $PATH.

myscript

Esto se ejecutará myscript si el archivo es ejecutable y se encuentra en algún directorio en $PATH.

source myscript

Esto será fuente myscript . El archivo no necesita ser ejecutable pero debe ser un script de shell válido. El archivo puede estar en el directorio actual o en un directorio en $PATH.

. myscript

Esto también será fuente myscript . Esta "ortografía" es la oficial tal como la define POSIX . Bash definido sourcecomo un alias para el punto.

Demostración

Considere myscript.shcon el siguiente contenido:

#!/bin/sh
# demonstrate setting a variable
echo "foo: "$(env | grep FOO)
export FOO=foo
echo "foo: "$(env | grep FOO)
# demonstrate changing of working directory
echo "PWD: "$PWD
cd somedir
echo "PWD: "$PWD

Antes de ejecutar el script, primero verificamos el entorno actual:

$ env | grep FOO
$ echo $PWD
/home/lesmana

La variable FOOno está definida y estamos en el directorio de inicio.

Ahora ejecutamos el archivo:

$ ./myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir

Verifique nuevamente el entorno:

$ env | grep FOO
$ echo $PWD
/home/lesmana

La variable FOOno está establecida y el directorio de trabajo no ha cambiado.

La salida del script muestra claramente que se configuró la variable y se cambió el directorio. La verificación posterior muestra que la variable no está establecida y el directorio no ha cambiado. ¿Que pasó? Los cambios se hicieron en un nuevo shell. El shell actual generó un nuevo shell para ejecutar el script. La secuencia de comandos se ejecuta en el nuevo shell y todos los cambios en el entorno surten efecto en el nuevo shell. Una vez que se completa el script, se destruye el nuevo shell. Todos los cambios en el entorno en el nuevo shell se destruyen con el nuevo shell. Solo el texto de salida se imprime en el shell actual.

Ahora nos abastecemos el archivo:

$ source myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir

Verifique nuevamente el entorno:

$ env | grep FOO
FOO=foo
$ echo $PWD
/home/lesmana/somedir

La variable FOO se establece y el directorio de trabajo ha cambiado.

Obtener el script no crea un nuevo shell. Todos los comandos se ejecutan en el shell actual y los cambios en el entorno tienen efecto en el shell actual.

Tenga en cuenta que en este ejemplo simple, el resultado de la ejecución es el mismo que el de la secuencia de comandos. Esto no es necesariamente siempre el caso.

Otra demostración

Considere la siguiente secuencia de comandos pid.sh:

#!/bin/sh
echo $$

(la variable especial se $$expande al PID del proceso actual de shell en ejecución)

Primero imprima el PID del shell actual:

$ echo $$
25009

Fuente del guión:

$ source pid.sh
25009

Ejecute el script, tenga en cuenta el PID:

$ ./pid.sh
25011

Fuente de nuevo:

$ source pid.sh
25009

Ejecutar de nuevo:

$ ./pid.sh
25013

Puede ver que el abastecimiento del script se ejecuta en el mismo proceso mientras se ejecuta el script crea un nuevo proceso cada vez. Ese nuevo proceso es el nuevo shell que se creó para la ejecución del script. Obtener el script no crea un nuevo shell y, por lo tanto, el PID permanece igual.

Resumen

Tanto el abastecimiento como la ejecución del script ejecutarán los comandos en el script línea por línea, como si escribiera esos comandos a mano línea por línea.

Las diferencias son:

  • Cuando ejecute el script, está abriendo un nuevo shell, escriba los comandos en el nuevo shell, copie la salida de nuevo en su shell actual y luego cierre el nuevo shell. Cualquier cambio en el entorno tendrá efecto solo en el nuevo shell y se perderá una vez que se cierre el nuevo shell.
  • Cuando obtiene el script, está escribiendo los comandos en su shell actual . Cualquier cambio en el entorno tendrá efecto y permanecerá en su shell actual.

Utilice la fuente si desea que el script cambie el entorno en su shell actualmente en ejecución. use ejecutar de otra manera.


Ver también:

lesmana
fuente
2
Un uso del abastecimiento es crear una forma rudimentaria de archivo de configuración para sus scripts. Comienza configurando varias variables a los valores predeterminados, y luego ingresa algo como myscript.conf, y ese script de origen puede tener instrucciones de asignación que anulen los valores que desee. Dado que el script de origen no comienza con # / bin / bash, no se recomienda ejecutarlo directamente.
LawrenceC
Entonces, la fuente es algo así como ejecutarla en un ámbito global, y la ejecución crea un nuevo ámbito local. ¿Se puede extender esto a una función en un script? ejecutar una función (normalmente) o "fuente"?
aliteralmind
2
¿Hay alguna diferencia entre usar source myscript.shy . myscript.sh?
Holloway
2
prácticamente no hay diferencia si usas bash. source es un alias para puntear en bash.
lesmana
1
Me encanta cuando la gente proporciona ejemplos tan elaborados para que incluso los novatos de Linux como yo puedan entender. ¡Gracias!
Julius
21

La ejecución de un script lo ejecuta en un proceso secundario separado, es decir, se invoca una instancia separada de shell para procesar el script. Esto significa que cualquier variable de entorno, etc., definida en el script no puede actualizarse en el shell padre (actual).

Obtener un script significa que es analizado y ejecutado por el propio shell actual. Es como si hubiera escrito el contenido del guión. Por esta razón, el script que se obtiene no necesita ser ejecutable. Pero tiene que ser ejecutable si lo está ejecutando, por supuesto.

Si tiene argumentos posicionales en el shell actual, no se modifican.

Entonces, si tengo un archivo que a.shcontiene:

echo a $*

y yo hago:

$ set `date`
$ source ./a.sh

Me sale algo como:

a Fri Dec 11 07:34:17 PST 2009

Mientras:

$ set `date`
$ ./a.sh

me da

a

Espero que ayude.

Alok
fuente
55
aunque esta respuesta es correcta en todos los sentidos, me resulta muy difícil de entender porque se demuestra utilizando otro concepto (establecer parámetros posicionales), que, en mi opinión, es aún más confuso que la diferencia de abastecimiento y ejecución.
lesmana
9

el abastecimiento es esencialmente lo mismo que escribir cada línea de la secuencia de comandos en el símbolo del sistema de una en una ...

La ejecución inicia un nuevo proceso y luego ejecuta cada línea de la secuencia de comandos, solo modificando el entorno actual por lo que devuelve.

John Weldon
fuente
6

Además de lo anterior, ejecutar el script como se ./myscriptrequiere permiso de ejecución para el archivo myscript mientras que el abastecimiento no requiere ningún permiso de ejecución. Es por eso chmod +x myscriptque no se requiere antessource myscript

abdominales
fuente
2
Es cierto, pero si eso es un problema, siempre puedes correr bash myscript.
Daniel Beck
5

El aprovisionamiento obtiene todas las variables adicionales definidas en el script.
Entonces, si tiene configuraciones o definiciones de funciones, debe obtenerlas y no ejecutarlas. Las ejecuciones son independientes del entorno de los padres.

Arkaitz Jiménez
fuente
3

Si recuerdo correcto, al ejecutar el script se ejecuta el ejecutable en la #!línea con el archivo del script como argumento (generalmente iniciando un nuevo shell y aprovisionando efectivamente el script en el nuevo shell, como con #!/bin/sh);
mientras que la fuente del script ejecuta cada línea en su entorno actual de shell, lo cual es útil para mutar su shell actual (por ejemplo, proporciona una forma de definir funciones de shell y exportar variables de entorno).

Shekhar
fuente
2

sourceEl comando ejecuta el script proporcionado (el permiso ejecutable no es obligatorio ) en el entorno actual del shell, mientras que ./ejecuta el script ejecutable proporcionado en un nuevo shell.

Además, verifique esta respuesta, por ejemplo: https://superuser.com/a/894748/432100

Vakharia dura
fuente