¿Cómo llamar a un script de shell desde otro script de shell?

739

Tengo dos scripts de shell a.shy b.sh.

¿Cómo puedo llamar b.shdesde el script de shell a.sh?

Praveen
fuente
8
¿Puede dar algunos detalles: qué sistema operativo y qué shell (s) o solo está hablando sobre ese problema en principio? El código de ejemplo también sería útil.
jsalonen
14
Esta no es realmente una pregunta específica ni demuestra un esfuerzo previo para resolver el problema.
Kris
1
Un problema que estaba teniendo era que b.shno tenía permisos de ejecución. Puede ser bueno comprobarlo.
seth10
Agregue ./antes del nombre del script, ejemplo, en su lugar: b.shuse:./b.sh
Benny
1
Si alguien sigue recibiendo el No such file or directoryerror stackoverflow.com/a/2920431/1356559
Amr Lotfy

Respuestas:

959

Hay un par de formas diferentes de hacer esto:

  1. Haga que el otro script sea ejecutable, agregue la #!/bin/bashlínea en la parte superior y la ruta donde está el archivo a la variable de entorno $ PATH. Entonces puedes llamarlo como un comando normal;

  2. O llámalo con el sourcecomando (alias es .) así source /path/to/script:;

  3. O utilizar el bashcomando para ejecutarlo: /bin/bash /path/to/script;

Los métodos primero y tercero ejecutan el script como otro proceso, por lo que las variables y funciones en el otro script no serán accesibles.
El segundo método ejecuta el script en el proceso del primer script, y extrae variables y funciones del otro script para que puedan utilizarse desde el script de llamada.

En el segundo método, si está utilizando un exitsegundo script, también saldrá del primer script. Lo que no sucederá en el primer y tercer método.

Algún tipo programador
fuente
30
recuerde chmod a+x /path/to/fileo de lo contrario no será ejecutable. Solo se aplica al método ./script.
Nathan Lilienthal
3
Recuerde cambiar el formato / codificación de los archivos ejecutables en Unix si se crean en DOS y luego se cargan en el entorno Unix -> dos2unix <nombre del script>
Abhishek Chatterjee
3
@cecemel La primera y la tercera forma podrían ser "asíncronas" utilizando la sintaxis normal de ejecución en segundo plano.
Algún tipo programador,
16
El problema sourcees que una exitdeclaración en el script llamado también saldrá del tuyo ...
Ohad Schneider
18
@ user528025 .no es un alias source, sino al revés. sourcees una extensión bash, mientras que .funciona en cualquier shell compatible con POSIX.
Score_Under
207

Mira esto.

#!/bin/bash
echo "This script is about to run another script."
sh ./script.sh
echo "This script has just run another script."
Budha
fuente
44
Esto supone que script.sh está en el mismo directorio que el script que se esté ejecutando. Si quisieras llamar a un guión en otro lugar, diríassh <path to script>/script.sh
Morgan Kenyon
32
Esto también usa dos proyectiles, bashy sh. Incluso cuando shes de hecho bash, no se comporta igual. Si está usando, #!/bin/bashentonces probablemente quiera usar bash script.sh(o simplemente ./script.shusar el hashbang de esos scripts).
Martin Tournoij
1
Seguí obteniendo permiso denegado error incluso cuando configuré el chmod +xarchivo .sh. ¿Alguna sugerencia?
Isaac resiste el
@isaacweathers prueba chmod 777
Janac Meena
114

Hay un par de formas en que puedes hacer esto. Terminal para ejecutar el script:

#!/bin/bash
SCRIPT_PATH="/path/to/script.sh"

# Here you execute your script
"$SCRIPT_PATH"

# or
. "$SCRIPT_PATH"

# or
source "$SCRIPT_PATH"

# or
bash "$SCRIPT_PATH"

# or
eval '"$SCRIPT_PATH"'

# or
OUTPUT=$("$SCRIPT_PATH")
echo $OUTPUT

# or
OUTPUT=`"$SCRIPT_PATH"`
echo $OUTPUT

# or
("$SCRIPT_PATH")

# or
(exec "$SCRIPT_PATH")

¡Todo esto es correcto para el camino con espacios!

Andrei Krasutski
fuente
41
¿Cuáles son sus diferencias? ¿Por qué uno, por qué otro?
rocketspacer
. Se prefiere "$ SCRIPT_PATH"
Harry Mumford-Turner
1
Solo puedo agregar que estos no son todos equivalentes, por ejemplo, sh "$ SCRIPT_PATH" y bash "$ SCRIPT_PATH" no ejecutarán el script #! / Usr / bin / expect, mientras que solo "$ SCRIPT_PATH" lo hará.
Tahlor
58

La respuesta que estaba buscando:

( exec "path/to/script" )

Como se mencionó, execreemplaza el shell sin crear un nuevo proceso. Sin embargo , podemos ponerlo en una subshell, que se hace usando las paréntesis.

EDITAR: En realidad ( "path/to/script" )es suficiente.

Maxim Chetrusca
fuente
11
Esto parece bastante complicado. ¿Por qué no simplemente llamarlo con /path/to/script? No veo la necesidad de execnada aquí?
Martin Tournoij
La subshell tampoco es necesaria ya que no estás execing.
Karel Vlk el
66
¿Cómo ejecutarías este script con argumentos?
Bhargav
Si aún desea capturar la salida del sub-script, intente $ (fuente "ruta / a / script")
cmcginty
@Bhargav sigue este enlace stackoverflow.com/questions/14302389/…
tpbafk
16

Depende de. Brevemente ... Si desea cargar variables en la consola actual y ejecutar, puede usar source myshellfile.shen su código. Ejemplo:

!#/bin/bash
set -x
echo "This is an example of run another INTO this session."
source my_lib_of_variables_and_functions.sh
echo "The function internal_function() is defined into my lib."
returned_value=internal_function()
echo $this_is_an_internal_variable

set +x

Si solo desea ejecutar un archivo y lo único que le interesa es el resultado, puede hacer lo siguiente:

!#/bin/bash
set -x
./executing_only.sh
sh i_can_execute_this_way_too.sh
bash or_this_way.sh
set +x

Espero te ayude. Gracias.

Douglas Bonafé
fuente
2
Tenga en cuenta que sourcees una característica específica de bash. La cáscara de bourne estándar solo tiene .(por ejemplo . other_script.sh).
Martin Tournoij
15

Puede usar /bin/shpara llamar o ejecutar otro script (a través de su script real):

 # cat showdate.sh
 #!/bin/bash
 echo "Date is: `date`"

 # cat mainscript.sh
 #!/bin/bash
 echo "You are login as: `whoami`"
 echo "`/bin/sh ./showdate.sh`" # exact path for the script file

El resultado sería:

 # ./mainscript.sh
 You are login as: root
 Date is: Thu Oct 17 02:56:36 EDT 2013
Ranjithkumar T
fuente
1
¿Seguramente esto se ejecutará showdate.shen / bin / sh en lugar de / bin / bash?
Chris Watts
He intentado con " /bin/sh ./showdate.sh", " /bin/bash ./showdate.sh", " ./showdate.sh" y ejecuté el archivo: mainscript.sh y obtuve el mismo resultado.
Ranjithkumar T
10

¡Simplemente agregue en una línea lo que haya escrito en un terminal para ejecutar el script!
p.ej:

#!bin/bash
./myscript.sh &

Si el script que se ejecutará no está en el mismo directorio, simplemente use la ruta completa del script.
por ejemplo: `/ home / user / script-directory /./ myscript.sh &

Luego
fuente
@Carpetsmoker &para la tarea en segundo plano
Andrei Krasutski
9

Primero debes incluir el archivo que llamas:

#!/bin/bash
. includes/included_file.sh

entonces llamas a tu función así:

#!/bin/bash
my_called_function
Ghazi Triki
fuente
9

Una fuente simple te ayudará. Por ej.

#!/bin/bash
echo "My shell_1"
source my_script1.sh
echo "Back in shell_1"
Nitin Jawarkar
fuente
9

Si tiene otro archivo en el mismo directorio, puede hacer lo siguiente:

bash another_script.sh

o

source another_script.sh

o

. another_script.sh

Cuando se usa en bashlugar de source, el script no puede alterar el entorno del script primario. El .comando es el estándar POSIX, mientras que el sourcecomando es un sinónimo bash más legible para .(prefiero sourcesobre .). Si su script reside en otro lugar, simplemente proporcione la ruta a ese script. Tanto la ruta relativa como la completa deberían funcionar.

Shital Shah
fuente
5

La respuesta principal sugiere agregar una #!/bin/bashlínea a la primera línea del subguión que se llama. Pero incluso si agrega el shebang, es mucho más rápido * ejecutar un script en un sub-shell y capturar la salida:

$(source SCRIPT_NAME)

Esto funciona cuando desea seguir ejecutando el mismo intérprete (por ejemplo, de bash a otro script bash) y garantiza que la línea shebang del subguión no se ejecute.

Por ejemplo:

#!/bin/bash
SUB_SCRIPT=$(mktemp)
echo "#!/bin/bash" > $SUB_SCRIPT
echo 'echo $1' >> $SUB_SCRIPT
chmod +x $SUB_SCRIPT
if [[ $1 == "--source" ]]; then
  for X in $(seq 100); do
    MODE=$(source $SUB_SCRIPT "source on")
  done
else
  for X in $(seq 100); do
    MODE=$($SUB_SCRIPT "source off")
  done
fi
echo $MODE
rm $SUB_SCRIPT

Salida:

~ ❯❯❯ time ./test.sh
source off
./test.sh  0.15s user 0.16s system 87% cpu 0.360 total

~ ❯❯❯ time ./test.sh --source
source on
./test.sh --source  0.05s user 0.06s system 95% cpu 0.114 total

* Por ejemplo, cuando se ejecutan herramientas de virus o seguridad en un dispositivo, puede llevar 100 ms extra ejecutar un nuevo proceso.

cmcginty
fuente
4
pathToShell="/home/praveen/"   
chmod a+x $pathToShell"myShell.sh"
sh $pathToShell"myShell.sh"
Abdennour TOUMI
fuente
4
 #!/bin/bash

 # Here you define the absolute path of your script

 scriptPath="/home/user/pathScript/"

 # Name of your script

 scriptName="myscript.sh"

 # Here you execute your script

 $scriptPath/$scriptName

 # Result of script execution

 result=$?
Valero
fuente
1
incorrecto para carpeta scriptPatho nombre de archivo scriptNamecon espacios
Andrei Krasutski
3

Suponga que el nuevo archivo es "/ home / satya / app / app_specific_env" y el contenido del archivo es el siguiente

#!bin/bash

export FAV_NUMBER="2211"

Agregue esta referencia de archivo al archivo ~ / .bashrc

source /home/satya/app/app_specific_env

Cuando reinicie la máquina o vuelva a iniciar sesión, intente echo $FAV_NUMBERen el terminal. Producirá el valor.

Por si acaso, si desea ver el efecto de inmediato, source ~/.bashrcen la línea de comando.

Satya Kalluri
fuente
3
chmod a+x /path/to/file-to-be-executed

Eso era lo único que necesitaba. Una vez que el script que se va a ejecutar se convierte en ejecutable de esta manera, usted (al menos en mi caso) no necesita ninguna otra operación adicional como sho ./mientras está llamando al script.

Gracias al comentario de @Nathan Lilienthal

Asqan
fuente
1

Hay algunos problemas para importar funciones desde otro archivo.
Primero : no necesita hacer este archivo ejecutable. ¡Mejor no hacerlo! solo agrega

. file

para importar todas las funciones. Y todos serán como si estuvieran definidos en su archivo.
Segundo : se puede definir la función con el mismo nombre. Se sobreescribirá. Es malo. Puedes declarar así

declare -f new_function_name=old_function_name 

y solo después de eso importamos. Entonces puede llamar a la función antigua por un nombre nuevo.
Tercero : puede importar solo la lista completa de funciones definidas en el archivo. Si algunos no son necesarios, puede desarmarlos. Pero si reescribe sus funciones después de desarmarlas, se perderán. Pero si establece una referencia a él como se describe anteriormente, puede restaurar después de desarmar con el mismo nombre.
FinalmenteEn el procedimiento común de importación es peligroso y no tan simple. ¡Ten cuidado! Puede escribir un script para hacer esto más fácil y seguro. Si usa solo una parte de las funciones (no todas), divídalas mejor en diferentes archivos. Lamentablemente, esta técnica no funcionó bien en bash. En python, por ejemplo, y en algunos otros lenguajes de script, es fácil y seguro. Es posible realizar una importación parcial solo las funciones necesarias con sus propios nombres. Todos queremos que en las próximas versiones de Bush se haga la misma funcionalidad. Pero ahora debemos escribir muchos bacalaos adicionales para hacer lo que quieras.

Anatoly
fuente
(¡Bienvenido a SO!) Como se vio por última vez al usuario Praveen en 2011, es difícil determinar si la pregunta era cómo hacer que el shell ejecute a.sh ejecute b.sh (y continúe ejecutando a.sh si no ordene lo contrario ), o para, literalmente, b.sh llamada . (Mi corrector ortográfico no se capta bush versions.) (¿Tienes a alguien a quien recurrir para que te ayude con la gramática del inglés? (A veces desearía haberlo hecho))
barba gris
0

Usa backticks.

$ ./script-that-consumes-argument.sh `sh script-that-produces-argument.sh`

Luego busque el resultado del script del productor como argumento en el script del consumidor.

dacabdi
fuente