Diferentes formas de ejecutar un script de shell


44

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?


Es bueno saberlo, gracias a sus preguntas y respuestas a continuación, especialmente las de Shawn. Me gustaría agregar algo que no era muy evidente para mí hasta que hice algunas pruebas. La inclusión de un "/" en la segunda forma anterior llevará el comando al modo 1 anterior. Es decir, mientras "./myscript.sh" sigue el modo 1, ". Myscript.sh" se adhiere al modo 2. Usted mencionó "usar la ruta (absoluta o relativa)", pero solo quería hacer esto evidente.
Arun

Respuestas:


32

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. Típicamente, 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 que cuando lo ejecuta, puede comportarse de manera diferente (o puede no funcionar 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 shell bash, sino uno muy similar llamado dash. Las secuencias de comandos que requieren bash pueden funcionar un poco mal cuando se llama haciendo /bin/sh scriptporque acaba de llamar una secuencia de comandos bash utilizando 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.


66
Decir "Ubuntu en realidad no usa el shell bash" es impreciso y técnicamente incorrecto. Ubuntu hace uso de la cáscara del golpe, el punto es que shcorresponde a dash, pero no a bash.
Faheem Mitha

@Shawn En el primer párrafo, escribió "Ejecuta el script en el lugar (como si hubiera copiado y pegado el script allí mismo). Esto significa que las funciones y variables no locales en el script permanecen". ¿Qué quieres decir con la segunda línea aquí? Puede usted explicar por favor.
Geek

@Geek cuando ejecuta un script como un proceso secundario (la forma normal), las variables y funciones que define (su entorno) desaparecen cuando el proceso finaliza. Si obtiene el script, esas variables y funciones se crean en el entorno actual; cuando finaliza el script, los cambios en el entorno permanecen.
Shawn J. Goff

@ ShawnJ.Goff gracias por la aclaración. +1.
Geek

Plot-twist: Bourne Shell (sh) solo acepta punto, no fuente, ya que es un bash-builtin. pubs.opengroup.org/onlinepubs/9699919799/utilities/… Entonces diría que la forma más portátil es un punto.
dezza

9

La mayoría de las personas depuran los scripts de shell agregando los siguientes 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), agregar una línea como set -x, guardar el archivo y luego ejecutar el archivo. Luego, cuando haya terminado, debe seguir los mismos pasos y eliminar 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
...
...

2
Un consejo relacionado: me he acostumbrado a poner emulate sh 2>/dev/nullen la parte superior de mis scripts de shell. Cuando se ejecuta con zsh, esto lo pone en modo compatible con POSIX. Cuando se ejecuta con otros proyectiles, la línea no tiene efecto. Entonces puedo ejecutar el script con zsh -x /path/to/script. Me gusta zsh aquí porque proporciona mejores trazas que bash o ksh.
Gilles 'SO- deja de ser malvado'

7

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

Ubuntu en realidad no usa el shell bash, sino uno muy similar llamado dash. Las secuencias de comandos que requieren bash pueden funcionar ligeramente mal cuando se llama haciendo /bin/shscript porque acaba de llamar una secuencia de comandos bash usando el intérprete de guiones.

Muchas secuencias de comandos del sistema (como en init.d, en / etc, etc.) tienen un shebang #!/bin/sh, pero /bin/shde hecho es un enlace simbólico a otro shell, en tiempos /bin/bashpasados, 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 de un tutorial de bash, coloque #!/bin/bashel título, 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 caparazón correcto.

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

cat foo.sh | dash
dash < foo.sh

5

.y sourceson 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 /bin/shcrea un nuevo proceso en el que se ejecutan comandos.


2
sh script
bash script

Estoy pensando si hay más ...

.y sourceson lo mismo Después de la ejecución, cualquier cambio de entorno scriptse 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, después de que el script salga, se mantendrá el directorio actual.


2
.solo funciona en sh / bash y shells relacionados. sourceTambién funciona en csh y shells relacionados.
KeithB

1

¿" Userland 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
. ./filename
# ( dot space dot slash filename )

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


1

. 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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.