Get the name of the caller script in bash script
BashShellBash Problem Overview
Let's assume I have 3 shell scripts:
script_1.sh
#!/bin/bash
./script_3.sh
script_2.sh
#!/bin/bash
./script_3.sh
the problem is that in script_3.sh
I want to know the name of the caller script.
so that I can respond differently to each caller I support
please don't assume I'm asking about $0
cause $0
will echo script_3
every time no matter who is the caller
here is an example input with expected output
-
./script_1.sh
should echoscript_1
-
./script_2.sh
should echoscript_2
-
./script_3.sh
should echouser_name or root or anything to distinguish between the 3 cases
?
Is that possible? and if possible, how can it be done?
this is going to be added to a rm
modified script... so when I call rm
it do something and when git
or any other CLI tool use rm
it is not affected by the modification
Bash Solutions
Solution 1 - Bash
Based on @user3100381's answer, here's a much simpler command to get the same thing which I believe should be fairly portable:
PARENT_COMMAND=$(ps -o comm= $PPID)
Replace comm=
with args=
to get the full command line (command + arguments). The =
alone is used to suppress the headers.
See: http://pubs.opengroup.org/onlinepubs/009604499/utilities/ps.html
Solution 2 - Bash
In case you are source
ing instead of calling/executing the script there is no new process forked and thus the solutions with ps
won't work reliably.
Use bash built-in caller
in that case.
$ cat h.sh
#! /bin/bash
function warn_me() {
echo "$@"
caller
}
$ cat g.sh
#!/bin/bash
source h.sh
warn_me "Error: You didn't do something"
$ . g.sh
Error: You didn't do something 3
g.sh
$
Solution 3 - Bash
The $PPID variable holds the parent process ID. So you could parse the output from ps to get the command.
#!/bin/bash
PARENT_COMMAND=$(ps $PPID | tail -n 1 | awk "{print \$5}")
Solution 4 - Bash
Based on @J.L.answer, with more in depth explanations (the only one command that works for me ([tag:linux])) :
cat /proc/$PPID/comm
gives you the name of the command of the parent [tag:pid]
If you prefer the command with all options, then :
cat /proc/$PPID/cmdline
explanations :
$PPID
is defined by the shell, it's the [tag:pid] of the parent processes- in
/proc/
, you have some dirs with the [tag:PID] of each process ([tag:linux]). Then, if youcat /proc/$PPID/comm
, you echo the command name of the PID
man proc
CheckSolution 5 - Bash
Couple of useful files things kept in /proc/$PPID here
/proc/*some_process_id*/exe
A symlink to the last executed command under some_process_id/proc/*some_process_id*/cmdline
A file containing the last executed command under some_process_id and null-byte separated arguments
So a slight simplification.
sed 's/\x0/ /g' "/proc/$PPID/cmdline"
Solution 6 - Bash
If you have /proc
:
$(cat /proc/$PPID/comm)
Solution 7 - Bash
You can simply use the command below to avoid calling cut/awk/sed:
ps --no-headers -o command $PPID
If you only want the parent and none of the subsequent processes, you can use:
ps --no-headers -o command $PPID | cut -d' ' -f1
Solution 8 - Bash
Declare this:
PARENT_NAME=`ps -ocomm --no-header $PPID`
Thus you'll get a nice variable $PARENT_NAME that holds the parent's name.
Solution 9 - Bash
You could pass in a variable to script_3.sh to determine how to respond...
script_1.sh
#!/bin/bash
./script_3.sh script1
script_2.sh
#!/bin/bash
./script_3.sh script2
script_3.sh
#!/bin/bash
if [ $1 == 'script1' ] ; then
echo "we were called from script1!"
elsif [ $1 == 'script2' ] ; then
echo "we were called from script2!"
fi