12

How can I determine if a script was invoked from a command line or via double-click in file manager (Nautilis)?

If the former, I still have a command prompt when the script finishes, but if it was double-clicked (or executed via a .desktop file), the script executes in a window and then disappears. I want the window to remain open with a command prompt.

I figure the script could make this check and either do nothing - if invoked from a command line - or exec bash at the end if invoked via double-click or .desktop.

Haven't been successful using methods to check if interactive or not or tty.

2
  • 1
    Have your .desktop file call your script in a command terminal and execute it. The first answer here with the line Exec=gnome-terminal -e "bash -c 'echo hello;$SHELL'" worked well when I tested it on my system. I changed the echo hello to my own script.
    – Terrance
    Feb 5, 2016 at 7:20
  • Note to future viewers, while the accepted answer by muru worked, the method in the comment by @Terrance is what I ultimately used.
    – tcashin
    Apr 4, 2018 at 18:08

4 Answers 4

9

You can check if the parent process is the shell. For example:

#! /bin/bash

if [[ $(readlink -f /proc/$(ps -o ppid:1= -p $$)/exe) != $(readlink -f "$SHELL") ]]
then 
    echo "Starting the shell..."
    exec "$SHELL"
else
    echo "Not starting a shell."
fi

ps -o ppid:1= -p $$ prints the PID of the parent process (ppid) of the current process (-p $$). A readlink on /proc/<pid>/exe should print the path to the executable, which would be the shell if you ran it in a shell, or something else otherwise.


Another possibility is the SHLVL variable, which indicates how nested the current the shell instance is. If run within a shell, the script should have SHLVL 2 or greater. When run by double clicking, or from a desktop launcher, it should be 1:

#! /bin/bash

if (( SHLVL > 1 ))
then 
    echo "Starting the shell..."
    exec "$SHELL"
else
    echo "Not starting a shell."
fi
4
  • The SHLVL option doesn't work for /bin/sh (dash) but the first option seems to work for both dash and bash.
    – tcashin
    Feb 8, 2016 at 18:56
  • @tcashin well, nobody uses dash as their interactive shell, and the question itself is tagged bash.
    – muru
    Feb 8, 2016 at 19:30
  • +1 for SHLVL as a platform-independent bash solution
    – Ed Randall
    Oct 9, 2018 at 16:02
  • Couldn’t the SHLVL also start with a value greater than 1 (in a file manager)? According to this RIP Tutorial article it’s not that platform independent. Jul 5, 2020 at 19:56
2

You can check if the shell script was run on a terminal by analyzing the output of tty command.

#! /bin/bash

if [[ $(tty) =~ "not a tty" ]]
then
    echo "Not running on terminal"

else
    echo "Running on terminal"
fi
4
  • 5
    That test can be simplified with -t 0 instead of $(tty) =~ ..., IIRC.
    – muru
    Apr 3, 2018 at 10:34
  • The -t 0 doesn't seem to work on /bin/sh or on my Ubuntu system.
    – James Ward
    Dec 20, 2023 at 19:08
  • @JamesWard. Are you sure. Did you try this command. [ -t 0 ] && echo "Terminal" || echo "Not a Terminal"
    – antman
    Jan 9 at 13:00
  • I guess it depends on what shell /bin/sh points to. On my system it was /bin/csh which says [: No match. The script does point out that bash is used.
    – James Ward
    Jan 9 at 16:47
0

When double clicked from Nautilus you won't have the entire environment setup like you do in a regular terminal session. I use this boilerplate code to prevent crashes: Desktop shortcut to Bash script crashes and burns . You can adapt it to your needs:

# $TERM variable may be missing when called via desktop shortcut
CurrentTERM=$(env | grep TERM)
if [[ $CurrentTERM == "" ]] ; then
    notify-send --urgency=critical "$0 cannot be run from GUI without TERM environment variable."
    exit 1
fi
-1

I checked the differences between the environment when running a script from the terminal and the environment when running a script by double-clicking it in Files;

When you run a script by double clicking in Files the $VTE_VERSION variable is unset, so you can hook to it to decide whether to replace the current Bash instance with an interactive one or not.

That is, just put this at the end of your script:

#! /bin/bash
# ...
[ ! -z $VTE_VERSION ] && exec bash

To make this work also in case the script is run from a desktop file, change the desktop file's Exec= line from say:

Exec=/path/to/script

To:

Exec=sh -c '/path/to/script; exec bash'

This way /path/to/script will be executed and sh will be replaced by Bash upon /path/to/script's completion.

You must log in to answer this question.

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