Exit terminal after running a bash script

Solution 1:

If you're opening just one file, you don't really need to use a script, because a script is meant to be an easy way to run multiple commands in a row, while here you just need to run two commands (including exit).

If you want to run exit after a command or after a chain of commands, you can chain it to what you have already by using the && operator (which on success of the previous command / chain of commands will execute the next command) or by using the ; operator (which both on success and on failure of the previous command / chain of commands will execute the next command).

In this case it would be something like that:

gnome-open <path_to_pdf_file> && exit

*<path_to_pfd_file> = path of the pdf file

exit put at the end of a script doesn't work because it just exits the bash instance in which the script is run, which is another bash instance than the Terminal's inner bash instance.

If you want to use a script anyway, the most straightforward way it's to just call the script like so:

<path_to_script> && exit

Or if the script is in the Terminal's current working directory like so:

./<script> && exit

If you really don't want to / can't do that, the second most straightforward way is to add this line at the end of your script:

kill -9 $PPID

This will send a SIGKILL signal to the to the script's parent process (the bash instance linked to the Terminal). If only one bash instance is linked to the Terminal, that being killed will cause Terminal to close itself. If multiple bash instances are linked to the Terminal, that being killed won't cause Terminal to close itself.

Solution 2:

This script terminates the terminal and thus the shell and himself.

It mercilessly kills all processes. If you have multiple tabs open in a terminal, then these are also closed.

The problem is, if several terminals are opened and these are child processes of gnome-terminal-server, all terminals will be killed.

In this case, the script should be started in an independent terminal, eg xterm

<your_command> & disown

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

    The PPID is the parent process id, in this case the shell (e.g. /bin/bash)

  • PPPID

    The PPPID is the parent process id of PPID, in this case, the terminal window

  • <your_command> & disown

    In the bash shell, the disown builtin command is used to remove jobs from the job table, or to mark jobs so that a SIGHUP signal is not sent to them if the parent shell receives it (e.g. if the user logs out).

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

    Gets the value of the fourth column of the file /proc/$PPID/stat (e.g. for /proc/1/stat it returns 0)

Solution 3:

You can use exec ./your-script.

A terminal emulator like GNOME Terminal quits when the initial process running inside it--which is usually a shell--quits.

If you are already in a terminal and the only thing you want to do before quitting that terminal is to run a particular script (or program), then this means you no longer really need the shell that's running in it anymore. Thus you can use the shell's exec builtin to make the shell replace itself with the process created by your command.

  • In the case of your script, that's another shell process--just as how a second shell process is created when you run a script without exec.

The syntax is exec command, e.g., exec ./your-script.

exec: an Example

For example, suppose I have a shell script called count, marked executable, and located in the current directory. It contains:

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

And, in a terminal, I run:

exec ./count

This prints the numerals 5, 4, 3, 2, and 1, one per second, and then the terminal window closes.

If you run this from something other than the first process run in your terminal--for example, if you ran bash first to start another shell instance--then this brings you back to the shell that created that process, rather than quitting the terminal. (This caveat applies equally to exit-based methods.)

You can use ./your-script; exit.

If you don't want to tell your shell to replace itself with the new process (via exec), you can tell it to stick around but quit itself immediately after the new process finishes.

To do this, run your command and the exit command, separated by ; so they can be given on one line.

The syntax is command; exit, e.g., ./your-script; exit.

command; exit vs. command && exit

You may notice this looks similar to the ./your-script && exit method suggested in kos's and heemayl's answers. The difference is that:

  • && runs the second command only if the first command reported that it succeeded by returning an exit code of zero.
  • ; runs the second command regardless of whether or not the first command reported success.

Which one you want depends on the specific situation. If the command fails, do you want the calling shell (and hosting terminal) to stay up? If so, use &&; if not, use ;.

There is also command || exit, which quits the calling shell only if command reported failure.

Solution 4:

You could source your script instead of running it e.g

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