¿Cuál es la diferencia entre el abastecimiento ('.' O 'fuente') y la ejecución de un archivo en bash?

76

¿Cuál es la diferencia entre ejecutar un script como este?

./test.sh

y ejecutando un script como este:

. test.sh?

Intenté un script simple de dos líneas para ver si podía encontrar si había alguna diferencia:

#!/bin/bash
ls

Pero ambos . test.shy ./test.shdevolvieron la misma información.

Natan
fuente
Disculpas si esto es un duplicado: tras una investigación más profunda, encontré algunas páginas con información relevante buscando 'bash dot' en lugar de 'bash'.
Natan
3
Así como test.shno es lo mismo que ./test.sh(el primero invoca una PATHbúsqueda), también lo es . test.shy es . ./test.shdiferente de la misma manera (el primero invoca una PATHbúsqueda). Muchas conchas parecen incluir implícitamente .al final de PATHcuando se hace una .búsqueda de ruta, pero este comportamiento no es estándar. Por lo tanto, es más exacto para comparar test.shvs . test.shy ./test.shvs . ./test.sh.
jw013

Respuestas:

83

./test.shse ejecuta test.shcomo un programa separado. Puede ser un script bash, si el archivo test.shcomienza con #!/bin/bash. Pero podría ser algo completamente distinto.

. ./test.shejecuta el código del archivo test.shdentro de la instancia en ejecución de bash. Funciona como si el archivo de contenido se test.shhubiera incluido textualmente en lugar de la . ./test.shlínea. (Casi: hay algunos detalles que difieren, como el valor $BASH_LINENOy el comportamiento de la returnconstrucción).

source ./test.shes idéntico a . ./test.shin bash (en otros shells, sourcepuede ser ligeramente diferente o no existir por completo; .para su inclusión está en el estándar POSIX).

La diferencia visible más común entre ejecutar un script separado ./test.she incluir un script con el .incorporado es que si el test.shscript establece algunas variables de entorno, con un proceso separado, solo se establece el entorno del proceso secundario, mientras que con la inclusión del script, el entorno del proceso de shell único se establece. Si se agrega una línea foo=baren test.sh, y echo $fooal final de la secuencia de comandos de llamada, verá la diferencia:

$ cat test.sh
#!/bin/sh
foo=bar
$ ./test.sh
$ echo $foo

$ . ./test.sh
$ echo $foo
bar
Gilles 'SO- deja de ser malvado'
fuente
17
Además, agregar echo $$al script mostrará la diferencia bastante clara. La $$variable contiene el PID del shell actual.
1
Otro escenario de uso es usar la . ./test.shllamada desde otro script de shell para usar funciones que se describen en test.sh. Quiero decir, no solo se pueden establecer variables, sino que también se pueden crear nuevas funciones de esta manera que luego se pueden llamar desde bash o algún otro script. . /usr/libexec/company/tools; custom_command "variable"
Rqomey
9

Ejecutar un script de la primera manera lo ejecuta como un proceso secundario. Sourcing (la segunda forma), por otro lado, ejecuta el script como si hubiera ingresado todos sus comandos en el shell actual: si el script establece una variable, permanecerá establecido, si el script sale, su sesión se cerrará. Ver help .para documentación.

choroba
fuente
3

Otra cosa que noto es que si tienes un alias como este:

# add into .bashrc_aliases
alias ls='ls -lht'

Con esto ./test.shobtendrá una lssalida normal (y un PID diferente que el shell actual)

auraham@pandora:~/iso$ ./test.sh 
dsl-4.4.10.iso  test.sh
3136 # PID

Con . test.sho . ./test.shobtendrá una salida más detallada (y el mismo PID que el shell actual):

auraham@pandora:~/iso$ echo $$
2767 # shell PID

auraham@pandora:~/iso$ . test.sh 
total 50M
drwxrwxr-x  2 auraham auraham 4.0K Jul 30 15:41 .
-rwxrwxr-x  1 auraham auraham   32 Jul 30 15:41 test.sh
drwxr-xr-x 50 auraham auraham 4.0K Jul 30 15:30 ..
-rw-rw-r--  1 auraham auraham  50M Jul 28 17:24 dsl-4.4.10.iso
2767 # PID
auraham
fuente
Puede incluir esto en .bashrc if [ -f ~/.bash_aliases ]; then . ~/.bash_aliases fi Luego, ingrese sus alias .bash_aliases.
auraham
Por supuesto, pero ¿aún no tienes que usar la aliaspalabra clave? (¿Tal vez eso es solo un error en tu publicación - en la línea 3?)
Emanuel Berg
totalmente correcto, mi error. Gracias @EmanuelBerg
auraham
-1

El uso principal para mí source(o .) es bash funciones .

Tengo scripts con muchas funciones y las ejecuto todas con mi .bashrc. Las funciones "se convierten" en comandos, que uso a menudo.

Willian Paixao
fuente
Probé los tres métodos en .bashrc - fuente, la posición absoluta del script y el nombre del comando (colocando el script en una carpeta PATH) - y los tres métodos funcionaron.
Emanuel Berg