Esci dal terminale dopo aver eseguito uno script bash


18

Sto cercando di scrivere uno bashscript per aprire determinati file (principalmente file pdf) usando il gnome-opencomando. Voglio anche che il terminale esca una volta aperto il file pdf.

Ho provato ad aggiungere exitalla fine del mio script che tuttavia non chiude il terminale. Ho provato a cercare online una risposta alla mia domanda, ma non sono riuscito a trovarne una vera e propria, lo apprezzerei davvero se voi ragazzi poteste aiutare.

Ho bisogno di una risposta che uccida solo il terminale dal quale eseguo il comando, non tutti i terminali sarebbero possibili? La risposta precedente che ho accettato uccide tutte le finestre del terminale aperte. Non mi ero reso conto che questo fosse il caso fino ad oggi.


Stai eseguendo lo script nel terminale in primo luogo? Rigorosamente dalla riga di comando, non c'è motivo di aprire il terminale per farlo.
Jacob Vlijm,

Sì, eseguo lo script dal terminale. Non mi rendevo conto che c'era una differenza tra terminale e linea di comando
Rumesh,

Ho sostituito il carattere gnome-opencon xdg-opennel mio script ma non ci sono cambiamenti. Il terminal rimane ancora aperto
Rumesh,

@ Tim Wow, funziona =) +1
AB

@Tim Ma la mia soluzione non era neanche male. ;)
AB

Risposte:


12

Se stai aprendo un solo file, non hai davvero bisogno di usare uno script, perché uno script è pensato per essere un modo semplice per eseguire più comandi di fila, mentre qui devi solo eseguire due comandi (incluso exit) .

Se si desidera eseguire exitdopo un comando o dopo una catena di comandi, è possibile collegarlo a ciò che si è già utilizzando l' &&operatore (che in caso di successo del comando / catena di comandi precedente eseguirà il comando successivo) o utilizzando il comando ;operatore (che sia in caso di successo che in caso di fallimento del comando / catena di comandi precedente eseguirà il comando successivo).

In questo caso sarebbe qualcosa del genere:

gnome-open <path_to_pdf_file> && exit

* <path_to_pfd_file> = percorso del file pdf

exitmesso alla fine di uno script non funziona perché esce semplicemente dall'istanza bashin cui viene eseguito lo script, che è un'altra bashistanza rispetto bashall'istanza interna del Terminale .

Se vuoi comunque usare uno script, il modo più semplice è semplicemente chiamare lo script in questo modo:

<path_to_script> && exit

O se lo script si trova nella directory di lavoro corrente del Terminale in questo modo:

./<script> && exit

Se davvero non vuoi / non puoi farlo, il secondo modo più semplice è aggiungere questa riga alla fine del tuo script:

kill -9 $PPID

Questo invierà un SIGKILLsegnale al processo genitore dello script (l' bashistanza collegata al Terminale). Se bashal Terminale è collegata solo un'istanza, quella uccisione causerà la chiusura del Terminale stesso. Se più bashistanze sono collegate al Terminale, quell'essere ucciso non farà chiudere il Terminale stesso.


2
Il segnale SIGTERM viene inviato a un processo per richiederne la chiusura. A differenza del segnale SIGKILL, può essere catturato, interpretato o ignorato dal processo. Ciò consente al processo di eseguire una buona terminazione rilasciando risorse e salvando lo stato, se appropriato. SIGINT è quasi identico a SIGTERM.
AB

@AB Hai ragione, SIGTERMqui non è abbastanza.
kos

Grazie per la risposta. Immagino che dovrei usare il solo comando che hai dato nella tua risposta
Rumesh,

kill $ PPID fa lo stesso di exit - niente. E uccidere -9 $ PPID chiude tutte le finestre figlio insieme al genitore.
SDsolar,

5

Questo script termina il terminale e quindi la shell e se stesso.

Uccide senza pietà tutti i processi. Se in un terminale sono aperte più schede, anche queste sono chiuse.

Il problema è che se vengono aperti più terminali e questi sono processi figlio di gnome-terminal-server, tutti i terminali verranno uccisi.

In questo caso, lo script dovrebbe essere avviato in un terminale indipendente, ad es xterm

<your_command> & disown

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

    Il PPID è l'id del processo parent, in questo caso la shell ( e.g. /bin/bash)

  • PPPID

    PPPID è l'ID del processo padre di PPID, in questo caso la finestra del terminale

  • <your_command> & disown

    Nella shell bash, il comando disown builtin viene utilizzato per rimuovere i lavori dalla tabella dei lavori o per contrassegnare i lavori in modo che un segnale SIGHUP non venga inviato loro se la shell padre lo riceve (ad es. Se l'utente si disconnette).

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

    Ottiene il valore della quarta colonna del file /proc/$PPID/stat(ad es. /proc/1/statPerché restituisce 0)


Penso che il comando $$ get sia il pid del terminale ... Sarebbe un'alternativa? Potresti anche spiegare come rinnegare?
Tim

Come lo fa questo script? Sono ancora nuovo agli script di shell, quindi non riesco davvero a capire quei comandi. Potresti spiegare come chiude il terminal
Rumesh,

1
@Tim No, restituisce la shell in un terminale: ps xa | grep $$=> 4381 pts/0 Ss 0:01 /usr/bin/zsh
AB

1
@RumeshSudhaharan Uccide l'intera finestra del terminale in cui viene avviato lo script, ma nessun'altra finestra del terminale.
AB

3
@AB in precedenza hai detto che questo uccide solo la finestra del terminale corrente e non nessuna delle altre. Ho usato questo script oggi con due finestre del terminale aperte ed entrambi sono stati uccisi una volta eseguito lo script.
Rumesh,

4

È possibile utilizzare .exec ./your-script

Un emulatore di terminale come GNOME Terminal si chiude quando termina il processo iniziale in esecuzione al suo interno, che di solito è una shell.

Se sei già in un terminale e l'unica cosa che vuoi fare prima di uscire da quel terminale è eseguire un particolare script (o programma), allora questo significa che non hai più davvero bisogno della shell che è in esecuzione in esso. Quindi puoi usare il execbuiltin della shell per fare in modo che la shell si sostituisca con il processo creato dal tuo comando.

  • Nel caso del tuo script, questo è un altro processo di shell, proprio come viene creato un secondo processo di shell quando esegui uno script senza exec.

La sintassi è , ad esempio, .exec commandexec ./your-script

exec: un esempio

Ad esempio, supponiamo di avere uno script di shell chiamato count, contrassegnato come eseguibile e situato nella directory corrente. Contiene:

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

E, in un terminale, corro:

exec ./count

Questo stampa il numeri 5, 4, 3, 2, e 1, una al secondo, e poi si chiude finestra di terminale.

Se lo esegui da qualcosa di diverso dal primo processo eseguito nel tuo terminale - ad esempio, se hai eseguito per bashprimo l'avvio di un'altra istanza della shell - questo ti riporta alla shell che ha creato quel processo, piuttosto che uscire dal terminale. (Questo avvertimento si applica ugualmente ai exitmetodi basati.)

È possibile utilizzare ../your-script; exit

Se non vuoi dire alla tua shell di sostituirsi con il nuovo processo (via exec), puoi dire che si attacca ma si chiude immediatamente al termine del nuovo processo.

Per fare ciò, esegui il tuo comando e il exitcomando, separati da in ;modo che possano essere dati su una riga.

La sintassi è command; exit, ad esempio, ../your-script; exit

command; exit vs. command && exit

Potresti notare che sembra simile al metodo suggerito nelle risposte di kos e di heemayl . La differenza è che:./your-script && exit

  • &&esegue il secondo comando solo se il primo comando ha riferito che è riuscito restituendo un codice di uscita pari a zero.
  • ; esegue il secondo comando a prescindere dal fatto che il primo comando abbia riscontrato o meno successo.

Quale vuoi dipende dalla situazione specifica. Se il comando fallisce, vuoi che la shell chiamante (e il terminale di hosting) rimanga attivo? In tal caso, utilizzare &&; in caso contrario, utilizzare ;.

C'è anche command || exit, che chiude la shell chiamante solo se commandsegnalato un errore .


2

Potresti procurarti il ​​tuo script invece di eseguirlo ad es

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

1

Personalmente avrei eseguito il comando per aprire pdf o altri file in subshell, mettere un ritardo per consentire l'apertura dei file e quindi uscire. Fondamentalmente, ecco cosa ho testato(nohup gnome-open *.pdf &); sleep 2; exit

Variazione su questo sarebbe nohup gnome-open *.pdf && sleep 2 && exit


Nel mio caso, poiché nohupignora il segnale di riaggancio, ha nohup xdg-open some_programfunzionato per me e exitnon è stato necessario. nohupreindirizza il messaggio a un nohup.outfile:nohup: ignoring input and appending output to nohup.out
nick indiessance

0

La soluzione più semplice sarebbe:

xdg-open file.pdf && exit

A differenza di altri comandi simili nohupnon è necessario per ignorare il comando SIGHUP, la ragione per cui xdg-openuscirà generando un processo figlio che è l'applicazione preferita per aprire il file pdf. Poiché il processo effettivo avviato dal terminale non è più lì per essere ucciso, nohupnon è necessario.

&&indica che il comando successivo verrà eseguito se il comando precedente ha esito positivo, ovvero restituisce il codice di uscita 0( $?=0) e exitchiuderà semplicemente il terminale.


Penso che abbia detto che l'uscita non funzionava ...
Tim

@Tim: Forse OP non l'ha usato nel modo giusto, dalla domanda non mi è molto chiaro come ha messo exitalla fine e non ha funzionato ..
heemayl

1
@Tim Perché OP ha inserito exitlo script, il che è inutile perché ha l'effetto di uscire bashdall'istanza in cui viene eseguito lo script piuttosto che dall'istanza principale bash(quella collegata al Terminale), che causerebbe invece la chiusura del Terminale
kos

1
Comunque xdg-openfunziona già in background e non collegato dal Terminale, quindi non è necessario nohupqui, oltre a ciò che intendo OP viene eseguito xdg-openpiù volte all'interno di uno script per aprire in batch più file, l'utilizzo in xdg-openquesto modo nello script causerebbe lo script per uscire alla prima xdg-openoccorrenza
kos

@kos: No, non sono in esecuzione xdg-opennel backgr, anche se l'ho avuto nohupè per un motivo diverso e deve essere lì .. ogni processo in background dal terminale di origine verrà interrotto quando si ucciderà il terminale padre .. nohupè lì per impedire come se non avessi bisogno di usare di nuovo il terminale in modo interattivo, non c'è bisogno di mettere il processo in bg .. sul tuo secondo punto che può anche essere evitato eseguendo ciascuno xdg-open && exitin una sottostruttura ..
heemayl

0

Per rispondere esplicitamente alla domanda sul titolo,

"Esci dal terminale dopo aver eseguito uno script bash" :

Esegui solo il tuo script nel terminale

Senza guardare ai dettagli che cosa fa lo script, uno script può essere eseguito direttamente all'interno di un terminale con l'opzione -e( --command), senza avviare una shell - viene utilizzato al posto della shell quindi:

gnome-terminal -e ./script.sh

Utilizzare l'opzione -x( --execute) quando si desidera fornire argomenti allo script. Con questo, solo l'intero resto della riga di comando viene preso come comando e argomenti.

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

Se lo script viene chiuso, non esiste alcuna shell interattiva in grado di contenere qualsiasi cosa in attesa dell'input dell'utente.

Esempi

Il teminale uscirà appena il comando in esecuzione termina al suo interno - in questo modo, chiudendo dopo che sleepè stato eseguito 4 secondi, senza shell:

gnome-terminal -x sleep 4

Ovviamente, puoi usare lo script di shell, perché lo script utilizza comunque un'istanza di shell diversa.

Inoltre, puoi eseguire una shell con uno script esplicito - non sarà interattivo:

gnome-terminal -x bash -c "echo 'Hello!'; sleep 4"
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.