Salga de la terminal después de ejecutar un script bash

18

Estoy tratando de escribir un bashscript para abrir ciertos archivos (en su mayoría archivos pdf) usando el gnome-opencomando. También quiero que la terminal salga una vez que abra el archivo pdf.

He intentado agregar exital final de mi script, sin embargo, eso no cierra el terminal. Intenté buscar en línea una respuesta a mi pregunta, pero no pude encontrar una adecuada, realmente lo agradecería si ustedes pudieran ayudar.

Necesito una respuesta que solo mate el terminal desde el que ejecuto el comando. No todos los terminales serían posibles. La respuesta anterior que acepté mata todas las ventanas de terminal que están abiertas. No me di cuenta de que este era el caso hasta hoy.

Rumesh
fuente
¿Estás ejecutando el script en la terminal en primer lugar? Estrictamente desde la línea de comandos, no hay razón para abrir el terminal para hacerlo.
Jacob Vlijm
Sí, ejecuto el script desde la terminal. No me di cuenta de que había una diferencia entre la terminal y la línea de comando
Rumesh
Reemplacé el gnome-opencon xdg-openen mi script pero no hay cambio. La terminal aún permanece abierta
Rumesh
@Tim Wow, funciona =) +1
AB
@Tim Pero mi solución tampoco fue mala. ;)
AB

Respuestas:

12

Si está abriendo solo un archivo, realmente no necesita usar un script, porque un script está destinado a ser una manera fácil de ejecutar múltiples comandos en una fila, mientras que aquí solo necesita ejecutar dos comandos (incluido exit) .

Si desea ejecutar exitdespués de un comando o después de una cadena de comandos, puede encadenarlo a lo que ya tiene usando el &&operador (que en caso de éxito del comando / cadena de comandos anterior ejecutará el siguiente comando) o usando el ;operador (que tanto en caso de éxito como en caso de fallo del comando / cadena de comandos anterior ejecutará el siguiente comando).

En este caso sería algo así:

gnome-open <path_to_pdf_file> && exit

* <path_to_pfd_file> = ruta del archivo pdf

exitponer al final de un script no funciona porque solo sale de la bashinstancia en la que se ejecuta el script, que es otra bashinstancia distinta de la bashinstancia interna de la Terminal .

Si de todos modos desea utilizar un script, la forma más sencilla es llamarlo de la siguiente manera:

<path_to_script> && exit

O si el script está en el directorio de trabajo actual de la Terminal de esta manera:

./<script> && exit

Si realmente no quiere / no puede hacer eso, la segunda forma más directa es agregar esta línea al final de su script:

kill -9 $PPID

Esto enviará una SIGKILLseñal al proceso principal del script (la bashinstancia vinculada a la Terminal). Si solo una bashinstancia está vinculada a la Terminal, el hecho de que se elimine hará que la Terminal se cierre. Si hay varias bashinstancias vinculadas a la Terminal, el hecho de que se elimine no hará que la Terminal se cierre sola.

kos
fuente
2
La señal SIGTERM se envía a un proceso para solicitar su terminación. A diferencia de la señal SIGKILL, el proceso puede detectarla e interpretarla o ignorarla. Esto permite que el proceso realice una terminación agradable liberando recursos y guardando el estado si es apropiado. SIGINT es casi idéntico a SIGTERM.
AB
@AB Tienes razón, SIGTERMaquí no es suficiente.
kos
Gracias por la respuesta. Supongo que solo
usaré
kill $ PPID hace lo mismo que exit: nada. Y kill -9 $ PPID cierra todas las ventanas secundarias junto con la principal.
SDsolar
5

Este script termina el terminal y, por lo tanto, el shell y él mismo.

Despiadadamente mata todos los procesos. Si tiene varias pestañas abiertas en una terminal, estas también están cerradas.

El problema es que si se abren varias terminales y estos son procesos hijos de gnome-terminal-server, todas las terminales se matarán.

En este caso, el script debe iniciarse en un terminal independiente, por ejemplo xterm

<your_command> & disown

PPPID=$(awk '{print $4}' "/proc/$PPID/stat")
kill $PPPID
  • PPID

    El PPID es la identificación del proceso padre, en este caso el shell ( e.g. /bin/bash)

  • PPPID

    El PPPID es el ID del proceso padre de PPID, en este caso, la ventana de terminal

  • <your_command> & disown

    En el shell bash, el comando incorporado disown se usa para eliminar trabajos de la tabla de trabajos o para marcar trabajos de modo que no se les envíe una señal SIGHUP si el shell padre lo recibe (por ejemplo, si el usuario cierra sesión).

  • awk '{print $4}' "/proc/$PPID/stat"

    Obtiene el valor de la cuarta columna del archivo /proc/$PPID/stat(por ejemplo, para /proc/1/statque devuelva 0)

AB
fuente
Creo que el comando $$ get es el pid del terminal ... ¿Sería una alternativa? ¿Podrías también explicar cómo repudiar?
Tim
¿Cómo hace eso este script? Todavía soy nuevo en los scripts de shell, así que realmente no puedo entender esos comandos. ¿Podría explicar cómo cierra la terminal
Rumesh
1
@Tim No, devuelve el shell en una terminal: ps xa | grep $$=> 4381 pts/0 Ss 0:01 /usr/bin/zsh
AB
1
@RumeshSudhaharan Mata toda la ventana de terminal en la que se inicia el script, pero ninguna otra ventana de terminal.
AB
3
@AB dijo anteriormente que esto solo mata la ventana de terminal actual y no ninguna de las otras. Utilicé este script hoy con dos ventanas de terminal abiertas y ambas fueron asesinadas una vez que ejecuté el script.
Rumesh
4

Puedes usar .exec ./your-script

Un emulador de terminal como GNOME Terminal se cierra cuando el proceso inicial que se ejecuta dentro de él, que generalmente es un shell, se cierra.

Si ya está en un terminal y lo único que desea hacer antes de salir de ese terminal es ejecutar un script (o programa) en particular, entonces esto significa que ya no necesita realmente el shell que se está ejecutando en él. Por lo tanto, puede usar la función execintegrada del shell para hacer que el shell se reemplace con el proceso creado por su comando.

  • En el caso de su script, ese es otro proceso de shell, tal como se crea un segundo proceso de shell cuando ejecuta un script sin él exec.

La sintaxis es , por ejemplo, .exec commandexec ./your-script

exec: un ejemplo

Por ejemplo, supongamos que tengo un script de shell llamado count, ejecutable marcado y ubicado en el directorio actual. Contiene:

#!/usr/bin/env bash
for i in {5..1}; do echo $i; sleep 1; done

Y, en una terminal, ejecuto:

exec ./count

Esto imprime los números 5, 4, 3, 2, y 1, uno por segundo, y entonces se cierra la ventana de terminal.

Si ejecuta esto desde algo que no sea el primer proceso ejecutado en su terminal, por ejemplo, si ejecutó bashprimero para iniciar otra instancia de shell, esto lo lleva de regreso al shell que creó ese proceso, en lugar de salir de la terminal. (Esta advertencia se aplica igualmente a los exitmétodos basados).

Puedes usar ../your-script; exit

Si no desea decirle a su shell que se reemplace con el nuevo proceso (vía exec), puede decirle que se quede pero se cierre inmediatamente después de que finalice el nuevo proceso.

Para hacer esto, ejecute su comando y el exitcomando, separados por ;para que se puedan dar en una línea.

La sintaxis es command; exit, por ejemplo, ../your-script; exit

command; exit vs. command && exit

Puede notar que esto se parece al método sugerido en las respuestas de kos y heemayl . La diferencia es que:./your-script && exit

  • &&ejecuta el segundo comando solo si el primer comando informó que tuvo éxito al devolver un código de salida de cero.
  • ; ejecuta el segundo comando independientemente de si el primer comando informó o no de éxito.

Cuál desea depende de la situación específica. Si el comando falla, ¿desea que el shell de llamada (y el terminal de alojamiento) permanezcan activos? Si es así, use &&; si no, úselo ;.

También existe command || exit, que sale del shell de llamada solo si se commandinforma un error .

Eliah Kagan
fuente
2

Puede obtener su script en lugar de ejecutarlo, por ejemplo

$ cat run.sh
exit;
$ ./run.sh #will not close
$ . ./run.sh # will close
RiaD
fuente
1

Personalmente, ejecutaría el comando para abrir pdf u otros archivos en subshell, retrasaría la apertura de los archivos y luego salir. Básicamente, esto es lo que he probado(nohup gnome-open *.pdf &); sleep 2; exit

La variación en esto sería nohup gnome-open *.pdf && sleep 2 && exit

Sergiy Kolodyazhnyy
fuente
En mi caso, ya que nohupignora la señal de colgar, nohup xdg-open some_programfuncionó para mí y no exitfue necesario. nohupredirige el mensaje a un nohup.outarchivo:nohup: ignoring input and appending output to nohup.out
nick indiessance
0

La solución más simple sería:

xdg-open file.pdf && exit

A diferencia de otro comando similar, nohupno es necesario hacer que el comando se ignore SIGHUP, la razón es que se xdg-opengenerará un proceso secundario, que es la aplicación preferida para abrir el archivo pdf. Como el proceso real iniciado desde la terminal ya no está allí para ser eliminado, nohupno es necesario.

&&indica que el siguiente comando se ejecutará si el comando anterior es exitoso, es decir, devuelve el código de salida 0( $?=0) y exitsimplemente cerrará el terminal.

heemayl
fuente
Creo que dijo que la salida no estaba funcionando ...
Tim
@Tim: Quizás OP no lo usó de la manera correcta, por la pregunta no está claro para mí cómo lo puso exital final y no funcionó ...
heemayl
1
@Tim Debido a que OP se coloca exitdentro del script, lo que no sirve de nada porque tiene el efecto de salir de la bashinstancia en la que se ejecuta el script en lugar de la bashinstancia principal (la vinculada al Terminal), lo que haría que el Terminal se cerrara en su lugar
kos
1
De todos modos, xdg-openya se ejecuta en segundo plano y desvinculado de la Terminal, por lo que no es necesario nohupaquí, además de lo que entiendo, OP se ejecuta xdg-openvarias veces dentro de un script para abrir por lotes múltiples archivos, usar xdg-openasí dentro del script causaría que el script a la salida de la primera xdg-openocurrencia
kos
@kos: No, no estoy ejecutando xdg-openen el backgr, incluso si lo hice nohupes por una razón diferente y debe estar allí ... cualquier proceso en segundo plano desde el terminal de origen se eliminará cuando mates el terminal principal ... nohupestá ahí para evitar es ... como no necesito usar el terminal de forma interactiva de nuevo, no hay necesidad de poner el proceso en bg ... en su segundo punto que también puede evitarse ejecutando cada uno xdg-open && exiten una subshell ...
heemayl
0

Para responder explícitamente la pregunta del título,

"Salir del terminal después de ejecutar un script bash" :

Ejecute solo su script en la terminal

Sin mirar los detalles de lo que hace el script, un script se puede ejecutar directamente dentro de un terminal con la opción -e( --command), sin iniciar un shell; se usa en lugar del shell y luego:

gnome-terminal -e ./script.sh

Use la opción -x( --execute) cuando desee proporcionar argumentos al script. Con esto, solo el resto de la línea de comandos se toma como comando y argumentos.

gnome-terminal -x ./script.sh foo bar

Si su secuencia de comandos se cierra, no hay un shell interactivo que pueda detener nada esperando la entrada del usuario.

Ejemplos

El terminal simplemente saldrá después de que salga el comando que se ejecuta en él, de esta manera, cerrando después de que se sleephaya ejecutado 4 segundos, sin shell:

gnome-terminal -x sleep 4

Por supuesto, aún puede usar scripts de shell, porque su script está utilizando una instancia de shell diferente de todos modos.

Además, puede ejecutar un shell con un script explícito; no será interactivo:

gnome-terminal -x bash -c "echo 'Hello!'; sleep 4"
Volker Siegel
fuente