Cualquier forma de salir del script bash, pero no salir de la terminal

183

Cuando uso el exitcomando en un script de shell, el script terminará el terminal (el indicador). ¿Hay alguna forma de terminar un script y luego permanecer en la terminal?

run.shSe espera que mi script se ejecute directamente a partir de otro script.

EDITAR: para ser más específicos, hay dos scripts run2.shcomo

...
. run.sh
echo "place A"
...

y run.shcomo

...
exit
...

cuando lo ejecuto . run2.sh, y si exittoca la línea de código run.sh, quiero que se detenga en la terminal y permanezca allí. Pero usando exit, toda la terminal se cierra.

PD: He intentado usar return, pero la línea de echocódigo aún se ejecutará ...

Ricardo
fuente
55
Realmente, realmente, realmente tengo que preguntar: ¿por qué usas exit en un script de fuente?
Ignacio Vazquez-Abrams
3
el comando de salida no debe terminar su sesión de terminal / inicio de sesión. si usas exit 0para terminar la secuencia de comandos después del éxito, cuando ejecutas tu secuencia de comandos ej: ./test.shdeberías ver la salida pero tu consola permanecerá abierta.
Ben Ashton
Podría usar el shellcomando, que de hecho abre un terminal de shell. Sin embargo, mi propia experiencia es que esto no sucede con exit. Salir normalmente devuelve el control al script principal.
Willem Van Onsem

Respuestas:

258

El "problema" realmente es que estás buscando y no ejecutando el script. Cuando obtiene un archivo, su contenido se ejecutará en el shell actual, en lugar de generar un subshell. Por lo tanto, todo, incluida la salida, afectará al shell actual.

En lugar de usar exit, querrás usar return.

Dominik Honnef
fuente
2
Aquí hay otra explicación que me pareció útil: askubuntu.com/a/53179/148337
3cheesewheel
Aunque correcto, esta no es una gran respuesta. Ignora que el script de llamada puede declarar variables o funciones a las que ese script llamado necesita acceso. Mejor explicar cómo configurar un código de retorno y luego procesarlo en runs.sh@ruakh tiene la mejor respuesta a esta pregunta.
MikeSchinkel
55
¿Qué pasa si la función es una llamada anidada? es decir, a llama a b, b llama a c, c quiere salir inmediatamente de a y b.
Michael
La fuente es casi lo mismo que copiar y pegar. Es mejor usar sh <script>o bash <script>si uno quiere ejecutar un script y terminar en algún momento
peterchaula
42

Si; puedes usar en returnlugar de exit. Su propósito principal es regresar de una función de shell, pero si la usa dentro de un sourcescript -d, regresa de ese script.

Como dice §4.1 "Bourne Shell Builtins" del Manual de referencia de Bash :

     return [n]

Hacer que una función de shell salga con el valor de retorno n . Si no se proporciona n , el valor de retorno es el estado de salida del último comando ejecutado en la función. Esto también puede ser utilizado para terminar la ejecución de un script que se está ejecutando con el .(o sourceincorporado), volviendo ya sea n o el estado de salida de la última orden ejecutada con el guión como el estado de salida de la secuencia de comandos. Cualquier comando asociado con la RETURNtrampa se ejecuta antes de que se reanude la ejecución después de la función o script. El estado de retorno no es cero si returnse usa fuera de una función y no durante la ejecución de un script por .o source.

ruakh
fuente
3
returnSOLO se puede usar desde una función. Si lo usa returny lo ejecuta como un script de shell (p sh run.sh. Ej. ), Bash informará de un error: return: can only devuelve 'desde una función o script de origen'
Tzunghsing David Wong
@TzungsingDavidWong: ¿Te das cuenta de que la mayor parte de esta respuesta es una cita del manual de referencia oficial? ¿Y que el mensaje de error que cita está de acuerdo con esta respuesta en lugar de con su reclamo?
ruakh
No estoy en desacuerdo contigo. Simplemente quiero señalar que returneso no funcionará si el script se ejecuta como un script de shell y no es ejecutado por. (o source) Por cierto, ¿dónde puedo encontrar el documento source -d?
Tzunghsing David Wong
9

En lugar de ejecutar el script usando . run2.sh, puede ejecutarlo usando sh run2.shobash run2.sh

Se iniciará un nuevo sub-shell, para ejecutar el script, se cerrará al final del script dejando abierto el otro shell.

Viorel Mirea
fuente
Si es así, ¿por qué el segundo parámetro sh "." run2.sh?
CHAN
@ H0WARD Tienes razón, olvidé eliminar los puntos. He editado la respuesta ahora.
Viorel Mirea
1
El OP establece explícitamente la fuente como un requisito.
Jonathan Neufeld
4

Puede agregar un comando de salida adicional después de la declaración / comando de retorno para que funcione para ambos, ejecutando el script desde la línea de comando y buscando desde el terminal.

Ejemplo de código de salida en el script:

   if [ $# -lt 2 ]; then
     echo "Needs at least two arguments"
     return 1 2>/dev/null
     exit 1
   fi

exitNo se llamará a la línea con el comando cuando obtenga el script después del returncomando.

Cuando ejecuta el script, el returncomando da un error. Entonces, suprimimos el mensaje de error enviándolo a /dev/null.

sin nombre
fuente
3

En realidad, creo que podrías estar confundido por cómo deberías hacerlo run a script.

Si usa shpara ejecutar una secuencia de comandos, por ejemplo, sh ./run2.shincluso si la secuencia de comandos incrustada termina con exit, su ventana de terminal permanecerá.

Sin embargo, si usa .o source, su ventana de terminal también se cerrará / cerrará cuando finalice el subíndice.

para obtener más detalles, consulte ¿Cuál es la diferencia entre usar shy source?

karl li
fuente
2

Esto es como si pusieras una función de ejecución dentro de tu script run2.sh. Utiliza el código de salida dentro de la ejecución mientras que la fuente de su archivo run2.sh en el bash tty. Si le da a la función de ejecución su poder para salir de su script y le da a run2.sh su poder para salir del terminador. Entonces, porque la función de ejecución tiene poder para salir de su teminador.

    #! /bin/sh
    # use . run2.sh

    run()
    {
        echo "this is run"
        #return 0
        exit 0
    }

    echo "this is begin"
    run
    echo "this is end"

De todos modos, apruebo con Kaz que es un problema de diseño.

Umae
fuente
No está claro en el texto qué intenta hacer esta respuesta, pero ciertamente no resuelve la pregunta en cuestión.
Luís de Sousa
2

Tuve el mismo problema y de las respuestas anteriores y de lo que entendí, lo que funcionó para mí fue:

  1. Tener una línea shebang que invoque el script deseado, por ejemplo,

    #!/bin/bashutiliza bashpara ejecutar el script

Tengo guiones con ambos tipos de shebang. Debido a esto, usar sho .no fue confiable, ya que condujo a una mala ejecución (como cuando el script rescata haber ejecutado de manera incompleta)

La respuesta por lo tanto, fue

    • Asegúrese de que el script tenga un shebang, para que no haya dudas sobre su controlador previsto.
    • chmod el archivo .sh para que pueda ejecutarse. (chmod +x file.sh)
    • Invocarlo directamente sin ninguno sho.

      (./myscript.sh)

Espero que esto ayude a alguien con una pregunta o problema similar.

gk_2000
fuente
1

Creo que esto sucede porque lo estás ejecutando en modo fuente con el punto

. myscript.sh

Deberías ejecutar eso en una subshell:

/full/path/to/script/myscript.sh

'fuente' http://ss64.com/bash/source.html

JBoy
fuente
No necesita la ruta completa al script si . myscript.shfunciona. A lo sumo, podría necesitar ./myscript.sh.
Álvaro González el
1

Es correcto que las secuencias de comandos de origen vs. ejecutadas usen returnvs. exitpara mantener abierta la misma sesión, como han señalado otros.

Aquí hay un consejo relacionado, si alguna vez desea un script que mantenga abierta la sesión, independientemente de si proviene o no.

El siguiente ejemplo se puede ejecutar directamente como foo.sho como . foo.sh/ source foo.sh. De cualquier manera, mantendrá la sesión abierta después de "salir". La $@cadena se pasa para que la función tenga acceso a los argumentos del script externo.

#!/bin/sh
foo(){
    read -p "Would you like to XYZ? (Y/N): " response;
    [ $response != 'y' ] && return 1;
    echo "XYZ complete (args $@).";
    return 0;
    echo "This line will never execute.";
}
foo "$@";

Resultado terminal:

$ foo.sh
$ ¿Te gustaría XYZ? (S / N): n
$. foo.sh
$ ¿Te gustaría XYZ? (S / N): n
$ |
(la ventana de terminal permanece abierta y acepta entradas adicionales)

Esto puede ser útil para probar rápidamente los cambios de script en un solo terminal mientras mantiene un montón de código de desecho debajo de la página principal exit/ returnmientras trabaja. También podría hacer que el código sea más portátil en cierto sentido (si tiene toneladas de scripts que se pueden invocar o no de diferentes maneras), aunque es mucho menos complicado usarlo returny, según exitcorresponda.

Beejor
fuente
0

Si su emulador de terminal no tiene -hold, puede desinfectar un script de origen y mantener el terminal con:

#!/bin/sh
sed "s/exit/return/g" script >/tmp/script
. /tmp/script
read

de lo contrario puedes usar $TERM -hold -e script

technosaurus
fuente
0

También asegúrese de regresar con el valor de retorno esperado. De lo contrario, si usa exit cuando encuentre una salida, saldrá de su shell base ya que la fuente no crea otro proceso (instancia).

codificador23
fuente
0

Para escribir un guión que es seguro para ser ejecutado ya sea como un script de shell o de origen como un archivo rc, el guión puede comprobar y comparar $0y $BASH_SOURCEy determinar si exitpueden usarse con seguridad.

Aquí hay un fragmento de código corto para eso

[ "X$(basename $0)" = "X$(basename $BASH_SOURCE)" ] && \
    echo "***** executing $name_src as a shell script *****" || \
    echo "..... sourcing $name_src ....."
Tzunghsing David Wong
fuente
-1

1) la salida 0 saldrá del script si tiene éxito.

2) la salida 1 saldrá del script si es una falla.

Puede probar estos dos anteriores en función de su solicitud.

Teja
fuente