Check if bash script was invoked from a shell or another script/application Check if bash script was invoked from a shell or another script/application shell shell

Check if bash script was invoked from a shell or another script/application


Try this:

ps -o stat= -p $PPID

If the result contains "s" (lowercase) it was either run from the command line or backgrounded from within a script. To tell those two apart:

ps -o stat= -p $$

will contain a "+" if it was not backgrounded.

Here's a table:

Run          $$    $PPIDCL           S+    SsCL&          S     Ss+Script       S+    S+Script&      S     SScript(&)    S     SsScript&(&)   S     NULL

Where (&) means the child script was backgrounded and & means the parent script (which is what "Script" refers to) that ran it was backgrounded. CL means command line. NULL means that ps output a null and that $PPID is "1".

From man ps:

   s    is a session leader   +    is in the foreground process group

It should be noted that this answer is based on GNU ps, but the man pages for BSD (including OS X) indicate similar functionality. And GNU ps is a hybrid that includes BSD functionality, among others.


I believe that what you really want to know is whether stdout is a terminal or not. If it is then you can (almost) safely assume that it's an interactive session. Try the following snippet:

if [[ -t 1 ]]; then        echo "Terminal"else        echo "Not-a-terminal"fi

The [[ -t 1 ]] command above is what checks if the file descriptor 1 (i.e. stdout) is a terminal or not.

EDIT:

Please note that this will indicate a non-terminal stdout if you pipe the output to some other program. In that case you might want a more versatile condition that will also check the standard input (file descriptor 0):

[[ -t 0 || -t 1 ]]


This is a function I adapted from another post about this topic. It matches all the parent processes up to the top against the items listed in the $shells variable. When it is done $iscli is set to either 0 or 1. If it is set to 0, then you know it was run from a shell or what you consider shell enough for this purpose. If it is set to 1, then you know a program was involved that is not approved. I use this for scripts I want to run in a shell and via PHP when I want different output to be provided to each.

You will of course need to call the function initially without any parameters before you need $iscli to have a value.

function top_level_parent_pid {    scriptname="${0##*/}"    shells="^bash|^init|^screen|^sh|^ssh|^su|${scriptname}"    pid=${1:-$$}    pidname="`ps --no-heading -o %c -p ${pid}`"    stat=($(</proc/${pid}/stat))    ppid=${stat[3]}    ppidname="`ps --no-heading -o %c -p ${ppid}`"    isclitest="`echo "${ppidname}" | grep -iv -E "${shells}"`"    until [ "${ppid}" -eq "1" ] || [ "${iscli}" = "1" ]; do            if [[ -n "${isclitest}" ]]; then                    iscli="1"                 else                    iscli="0"                    top_level_parent_pid ${ppid}            fi    done}