29

I am trying to write a bash script to open certain files (mostly pdf files) using the gnome-open command. I also want the terminal to exit once it opens the pdf file.

I have tried adding exit to the end of my script however that does not close the terminal. I did try to search online for an answer to my question but I couldn't find any proper one, I would really appreciate it if you guys could help.

I need an answer that only kills the terminal from which I run the command not all the terminals would this be possible? The previous answer which I accepted kills all the terminal windows that are open. I did not realize this was the case until today.

10
  • Are you running the script in the terminal in the first place? Strictly from command line, there is no reason to open the terminal to do so. Apr 20, 2015 at 13:40
  • Yes I run the script from the terminal. I didnt realize there was a difference between terminal and command line
    – Rumesh
    Apr 20, 2015 at 13:59
  • I replaced the gnome-open with xdg-open in my script but there is no change. The terminal still remains open
    – Rumesh
    Apr 20, 2015 at 14:07
  • @Tim Wow, it works =) +1
    – A.B.
    Apr 20, 2015 at 15:52
  • @Tim But my solution was not bad either. ;)
    – A.B.
    Apr 20, 2015 at 16:00

8 Answers 8

24

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.

5
  • 3
    The SIGTERM signal is sent to a process to request its termination. Unlike the SIGKILL signal, it can be caught and interpreted or ignored by the process. This allows the process to perform nice termination releasing resources and saving state if appropriate. SIGINT is nearly identical to SIGTERM.
    – A.B.
    Apr 20, 2015 at 15:42
  • 1
    @A.B. You're right, SIGTERM here is not enough.
    – kos
    Apr 20, 2015 at 15:45
  • Thanks for the reply. I guess ill just use the single command you gave in your answer
    – Rumesh
    Apr 22, 2015 at 8:00
  • kill $PPID does the same as exit - nothing. And kill -9 $PPID closes all the child windows along with the parent.
    – SDsolar
    Jul 25, 2017 at 3:07
  • +1 for use of kill -9 $PPID When using the GUI option "Run in Konsole" in Debian 11, terminal does not close when using a plan old exit Oct 6, 2021 at 1:23
8

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.

0
6

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)

17
  • I think the command $$ get's the pid of the terminal... Would that be an alternative? Could you also explain how to disown?
    – Tim
    Apr 20, 2015 at 13:59
  • How does this script do that? I am still new to shell scripting so I cant really understand those commands. Could you please explain how it closes the terminal
    – Rumesh
    Apr 20, 2015 at 14:10
  • 1
    @Tim No, it returns the shell in a terminal: ps xa | grep $$ => 4381 pts/0 Ss 0:01 /usr/bin/zsh
    – A.B.
    Apr 20, 2015 at 14:39
  • 1
    @RumeshSudhaharan It kills the entire terminal window in which the script is started, but no other terminal windows.
    – A.B.
    Apr 20, 2015 at 15:36
  • 3
    @A.B. you previously said that this only kills the current terminal window and not any of the others. I used this script today with two terminal windows open and both of them were killed once I ran the script.
    – Rumesh
    Apr 22, 2015 at 7:02
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
2

Personally I would execute the command to open pdf or other files in subshell, put a delay to let the files open, and then exit. Basically, here's what I've tested (nohup gnome-open *.pdf &); sleep 2; exit

Variation on this would be nohup gnome-open *.pdf && sleep 2 && exit

1
  • In my case, since nohup ignores the hangup signal, nohup xdg-open some_program worked for me, and exit was unneeded. nohup redirects message to a nohup.out file: nohup: ignoring input and appending output to nohup.out Sep 12, 2019 at 15:36
1

The simplest solution would be:

xdg-open file.pdf && exit

Unlike other similar command nohup is not needed to make the command ignoring SIGHUP, the reason being xdg-open will exit spawning a child process which is preferred application to open the pdf file. As the actual process started from the terminal is no longer there to be killed, nohup is not needed.

&& indicates the next command will be run if the previous command is successful i.e. returns the exit code 0 ($?=0) and exit will simply close the terminal.

11
  • I think he said exit wasn't working...
    – Tim
    Apr 20, 2015 at 16:09
  • @Tim: Perhaps OP did not use it the right way, from the question its very unclear to me how did he/she put exit at the end and did not work..
    – heemayl
    Apr 20, 2015 at 16:13
  • 1
    @Tim Because OP put exit inside the script, which is unuseful because it has the effect of exiting the bash instance in which the script is being executed rather then the parent bash instance (the one linked to the Terminal), which would cause the Terminal to close instead
    – kos
    Apr 20, 2015 at 19:54
  • 1
    Anyway xdg-open runs already in the background and unlinked from the the Terminal, so you don't need nohup here, plus from what I understand OP runs xdg-open multiple times inside a script to batch-open multiple files, using xdg-open like that inside the script would cause the script to exit at the first xdg-open occurence
    – kos
    Apr 20, 2015 at 20:04
  • @kos: No, i am not running xdg-open in the backgr, even if i had nohup is for a different reason & must be there..any background process from originating terminal will be killed when you will kill the parent terminal..nohup is there to prevent it..as i don't need to use the terminal interactively again, there is no need to put the process in bg..on your 2nd point that can also be prevented by running each xdg-open && exit in a subshell..
    – heemayl
    Apr 20, 2015 at 20:12
1

To explicitly answer the title question,

"Exit terminal after running a bash script":

Run only your script in the terminal

Without looking at the details what the script does, a script can be directly run inside a terminal with the option -e (--command), without starting a shell - it is used instead of the shell then:

gnome-terminal -e ./script.sh

Use the option -x (--execute) when you want to provide arguments to the script. With this, just the whole remainder of the commandline is taken as command and arguments.

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

If your script exits, there is no interactive shell that could hold up anything by waiting for user input.

Examples

The teminal will just exit after the command running in it exits - like this, closing after sleep has run 4 seconds, with no shell:

gnome-terminal -x sleep 4

Of course, you can stil use shell scripting, because your script is using a different shell instance anyway.

Also, you can run a shell with an explicit script - it will not be interactive:

gnome-terminal -x bash -c "echo 'Hello!'; sleep 4"
0

With "When script exits, close terminal" in the terminal settings, I place this at the bottom of an executable bash script to close it:

echo "Automatically Closing in 3 seconds..."

sleep 3

exit

read # show terminal output

When I put the exit after the read, script and terminal window don't close.

Another nice one that I often use to reload a script from its startpoint in the same terminal:

echo "Enter = Restart"
echo "Ctrl+c or Close button to Close"

read

exec bash "$0" "$@" # Restart script from the beginning

Here the restarting rule follows 'read'.

Cheerio.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .