¿Cuál es la diferencia entre "fuente x", ". x "y" ./x "en Bash?

11

Tengo una fuente bash de la run.shsiguiente manera,

#!/bin/bash
if [ $# -ne 1 ]; then
    exit
fi
...

cuando lo ejecuto de dos maneras, hay diferentes comportamientos. La primera forma es

source run.sh

Cerrará la terminal después de la ejecución. La segunda forma es

./run.sh

esto simplemente terminará de ejecutar el script y permanecerá en la terminal. Estoy preguntando si hay un comando para salir de un script bash para ambos source run.shy para la ./run.shejecución. También lo he intentado return, lo que no funciona bien en ./run.shejecución.

En términos más generales, me interesa saber por qué sucede esto y cuál es la diferencia entre usar "fuente" y "". para la ejecución del script?

Ricardo
fuente

Respuestas:

16

Antes de responder, creo que se necesitan algunas aclaraciones. Analicemos las siguientes tres líneas:

source run.sh
. run.sh
./run.sh

Las dos primeras líneas son exactamente idénticas: .de hecho, es un alias para source. Lo que sourcehace es ejecutar el script de shell en el contexto actual, por lo tanto, una llamada a exitcerrará el shell.

Sin embargo, la tercera línea (que es la que te confunde) no tiene nada que ver con las otras líneas. ./run.shes solo una ruta y es igual que (por ejemplo) /home/user/run.sho /usr/bin/something. Recuerde siempre que los comandos en el shell están separados por un espacio. Entonces, en este caso, el comando no es ., pero es ./run.sh: esto significa que se ejecutará un sub-shell y que exittendrá efecto solo en el sub-shell.

Andrea Corbellini
fuente
5

Tres maneras:

Puede encerrar el script en una función y solo usar return.

#!/usr/bin/env bash
main() {
    ...
    return 1
    ...
}
main "$@"

Puede probar si el script proviene de un shell interactivo.

if [[ $- = *i* ]]; then
    return 1
else
    exit 1
fi

Puede intentar regresar y, si falla, salir.

return 1 2>/dev/null || exit 1
geirha
fuente
¿Alguna pista sobre cómo funciona el encantamiento mágico $- = *i* ?
deadbeef404
@ deadbeef404 El parámetro especial -contiene los indicadores de opción actualmente activos. La prueba verifica si la -ibandera está activa. Ver gnu.org/software/bash/manual/html_node/Special-Parameters.html
geirha
1

Piense en el comando 'fuente' como en la declaración 'incluir'. Toma el contenido del argumento y lo ejecuta como si se ejecutara directamente. En este caso, su comando es 'fuente' con un argumento de 'run.sh' y run.sh se ejecuta exactamente como si hubiera escrito el contenido de run.sh en su línea de comando.

Cuando ejecuta './run.sh', './run.sh' es su comando y no tiene argumentos. Como este archivo es de texto plano y no binario, su shell busca un intérprete en shebang ('#!' En la primera línea) y encuentra '/ bin / bash'. Entonces su shell inicia una nueva instancia de bash y el contenido de run.sh se ejecuta dentro de esta nueva instancia.

En primera instancia, cuando bash alcanza el comando 'salir', se ejecuta exactamente como si lo hubiera escrito en la línea de comando. En las segundas instancias se ejecuta en el proceso bash que inició su shell, por lo que solo esta instancia de bash recibe un comando de 'salida'.

Cuando escribe una línea en bash, cualquier cosa antes del primer espacio se trata como un comando y todo lo que sigue se trata como argumentos. El comando '.' es un alias de 'fuente'. Cuando corres '. run.sh 'the'. ' es un comando en sí mismo ya que está separado de sus argumentos por un espacio. Cuando ejecuta './run.sh', su comando es './run.sh' y '.' es parte de la ruta relativa a run.sh con el '.' representando su carpeta actual.

fuma2345
fuente
Si usted es un programador de C / C ++ que busca mejorar con las secuencias de comandos de shell / bash, esta es la respuesta perfecta.
Justin