it-swarm-es.tech

Diferentes formas de ejecutar un script de Shell

Hay varias formas de ejecutar un script, las que conozco son:

/path/to/script # using the path (absolute or relative)
. script        # using the . (dot)
source script   # using the `source` command

¿Son más de esto? Cuáles son las diferencias entre ellos? ¿Hay situaciones en las que debo usar una y no otra?

44
phunehehe

Otra forma es llamar al intérprete y pasarle la ruta al script:

/bin/sh /path/to/script

El punto y la fuente son equivalentes. (EDITAR: no, no lo son: como KeithB señala en un comentario sobre otra respuesta, "." Solo funciona en shells relacionados con bash, donde "source" funciona en shells relacionados con bash y csh). Ejecuta el script en -place (como si hubiera copiado y pegado el script allí). Esto significa que las funciones y variables no locales en el script permanecen. También significa que si el script hace un CD en un directorio, todavía estará allí cuando esté listo.

Las otras formas de ejecutar un script lo ejecutarán en su propia subshell. Las variables en el script aún no están vivas cuando se hace. Si el script cambió de directorio, entonces no afecta el entorno de llamada.

/ path/to/script y/bin/sh script son ligeramente diferentes. Normalmente, un script tiene un "Shebang" al principio que se ve así:

#! /bin/bash

Este es el camino hacia el intérprete de guiones. Si especifica un intérprete diferente al que lo hace cuando lo ejecuta, entonces puede comportarse de manera diferente (o puede que no funcione en absoluto).

Por ejemplo, los scripts de Perl y Ruby comienzan con (respectivamente):

#! /bin/Perl

y

#! /bin/Ruby

Si ejecuta uno de esos scripts ejecutando /bin/sh script, entonces no funcionarán en absoluto.

Ubuntu en realidad no usa el bash Shell, sino uno muy similar llamado dash. Las secuencias de comandos que requieren bash pueden funcionar ligeramente mal cuando se llama haciendo /bin/sh script porque acabas de llamar un script bash usando el intérprete de guiones.

Otra pequeña diferencia entre llamar al script directamente y pasar la ruta del script al intérprete es que el script debe estar marcado como ejecutable para ejecutarlo directamente, pero no para ejecutarlo pasando la ruta al intérprete.

Otra variación menor: puede prefijar cualquiera de estas formas de ejecutar un script con eval, por lo tanto, puede tener

eval sh script
eval script
eval . script

y así. En realidad no cambia nada, pero pensé que lo incluiría por minuciosidad.

32
Shawn J. Goff

La mayoría de las personas depuran los scripts de Shell agregando lo siguiente indicadores de depuración al script:

set -x     # Print command traces before executing command.
set -v     # Prints Shell input lines as they are read.
set -xv    # Or do both

Pero esto significa que debe abrir el archivo con un editor (suponiendo que tenga permisos para editar el archivo), agregando una línea como set -x, guarde el archivo, luego ejecute el archivo. Luego, cuando haya terminado, debe seguir los mismos pasos y eliminar el set -x, etc. etc. Esto puede ser tedioso.

En lugar de hacer todo eso, puede establecer los indicadores de depuración en la línea de comandos:

$ bash -x ~/bin/ducks
+ du -cks -x dir1 dir2 dir3 file1 file2 file3
+ sort -n
+ tail .ducks
123 etc
424 bin
796 total



$ sh -xv ~/bin/ducks  
#!/usr/bin/env bash

# Find the disk hog
# Borrowed from http://oreilly.com/pub/h/15
...
...
9
Stefan Lasiewski

Shawn J. Goff hizo muchos puntos buenos, pero no incluyó toda la historia:

Ubuntu en realidad no usa el bash Shell, sino uno muy similar llamado dash. Las secuencias de comandos que requieren bash pueden funcionar ligeramente mal cuando se llama haciendo /bin/sh script porque acabas de llamar a un script bash usando el intérprete de guiones.

Muchos scripts del sistema (como en init.d, en/etc, etc.) tienen un Shebang #!/bin/sh, pero /bin/sh es, de hecho, un enlace simbólico a otro Shell - en tiempos anteriores /bin/bash, hoy en día /bin/dash. Pero cuando uno de ellos se invoca como /bin/sh, se comportan de manera diferente, es decir, se adhieren al modo de compatibilidad POSIX.

¿Cómo lo hacen? Bueno, inspeccionan cómo fueron invocados.

¿Puede un shellscript probar cómo se invocó y hacer diferentes cosas, dependiendo de eso? Sí puede. Entonces, la forma en que lo invocas siempre puede conducir a resultados diferentes, pero por supuesto, rara vez se hace para molestarte. :)

Como regla general: si está aprendiendo un Shell específico como bash y escribe comandos desde un tutorial de bash, ponga #!/bin/bash en el titular, no #!/bin/sh, excepto donde se indique lo contrario. De lo contrario, sus comandos podrían fallar. Y si no ha escrito un guión usted mismo, invoque directamente (./foo.sh, bar/foo.sh) en lugar de adivinar un Shell (sh foo.sh, sh bar/foo.sh). El Shebang debería invocar el Shell correcto.

Y aquí hay otros dos tipos de invocación:

cat foo.sh | dash
dash < foo.sh
7
user unknown

. y source son equivalentes porque no generan un subproceso sino que ejecutan comandos en el Shell actual. Esto es importante cuando el script establece variables de entorno o cambia el directorio de trabajo actual.

Usar la ruta o dársela a /bin/sh crea un nuevo proceso en el que se ejecutan comandos.

5
mouviciel
sh script
bash script

Estoy pensando si hay más ...

. y source son iguales. Después de la ejecución, cualquier cambio de entorno en script se mantendría. Por lo general, se usaría para obtener una biblioteca Bash, por lo que la biblioteca se puede reutilizar en muchos scripts diferentes.

También es una buena manera de mantener el directorio actual. Si cambia el directorio en el script, no se aplicará en el Shell donde ejecuta ese script. Pero si lo busca para ejecutarlo, una vez que finalice el script, se mantendrá el directorio actual.

2
livibetter

. y la fuente son un poco diferentes en zsh al menos (eso es lo que uso) porque

source file

Funciona, mientras

. file

no, necesita

. ./file
1
bollovan
. ./filename
# ( dot space dot slash filename )

Ejecuta el script en el Shell actual cuando el directorio no está en la ruta.

1
jrh_enginnering

¿" serland exec " cuenta como una forma diferente? Userland exec carga el código y lo ejecuta sin el uso de una llamada al sistema execve ().

1
Bruce Ediger