views:

9253

answers:

11

How can I determine the name of the bash script file inside the script itself?
Like if my script is in file runme.sh, than how would I make it to display "You are running runme.sh" message without hardcodding that?

Thanks,

+28  A: 
me=`basename $0`

For reading through a symlink, which is usually not what you want (you usually don't want to confuse the user this way), try:

me="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"

IMO, that'll produce confusing output. "I ran foo.sh, but it's saying I'm running bar.sh!? Must be a bug!" Besides, one of the purposes of having differently-named symlinks is to provide different functionality based on the name it's called as (think gzip and gunzip on some platforms).

Tanktalus
Nice flourish with the basename there.
dmckee
$0 gives you the name via which the script was invoked, not the real path of the actual script file.
Chris Conway
It works unless you're being called via symlink. But, even then, it's usually what you want anyway, IME.
Tanktalus
You can be called by a name that doesn't exist as a file at all -- most common example, calling sh as "-/bin/sh" causes it to act as a login shell. See `exec -a` in Bash, or `execvp("/bin/foo", {"blah", ...})`.
ephemient
Yes, that's a better example.
Chris Conway
If your script changes its behavior based on how its called, its a good idea to ensure some catch all when evaluating $0 .. otherwise, a simple symlink could make it do odd things :) I.e. if the link was named foobar and the script only accounts for foo or bar.
Tim Post
A: 

echo "You are running $0"

mmacaulay
+3  A: 

You can use $0 to determine your script name (with full path) - to get the script name only you can trim that variable with

basename $0
VolkA
+16  A: 

If the script name has spaces in it, a more robust way is to use "$0" or "$(basename "$0")" to prevent the name from getting mangled or interpreted in any way. In general, it is good practice to always quote variable names in the shell.

jleedev
(Better answer then the one thats getting all the votes!)
slashmais
(Agreed! But why are we talking parenthetically?)
ephemient
(IME, it's rare that it's important, which is why my answer didn't bother with the quotes.)
Tanktalus
+1  A: 

$0 doesn't answer the question (as I understand it). A demonstration:

$ cat script.sh
#! /bin/sh
echo `basename $0`
$ ./script.sh 
script.sh
$ ln script.sh linktoscript
$ ./linktoscript 
linktoscript

How does one get ./linktoscript to print out script.sh?

[EDIT] Per @ephemient in comments above, though the symbolic link thing may seem contrived, it is possible to fiddle with $0 such that it does not represent a filesystem resource. The OP is a bit ambiguous about what he wanted.

Chris Conway
added answer to this to my answer above, but I disagree that this is what's really wanted (or that you should want it, barring some extenuating circumstances that I can't currently fathom)
Tanktalus
I think that printing linktoscript instead of script.sh is a feature, not a bug. Several unix commands use their name for altering their behaviour. An example is vi/ex/view.
mouviciel
@Tanktalus: There are cases where you want the behaviour to change based on the real location of the file -- on a previous project I had an "Active branch" script, which would symlink in to the path several tools from the branch I was working on; those tools could then find out which directory they'd been checked out into to run against the right files.
Andrew Aylett
+5  A: 

To answer Chris Conway, on Linux (at least) you would do this:

echo $(basename $(readlink -nf $0))

readlink prints out the value of a symbolic link. If it isn't a symbolic link, it prints the file name. -n tells it to not print a newline. -f tells it to follow the link completely (if a symbolic link was a link to another link, it would resolve that one as well).

Travis B. Hartwell
-n is harmless but not necessary because $(...) structure will trim it.
赵如飞
+5  A: 

If you want it without the path then you would use ${0##*/}

Mr. Muskrat
+1 So you read the bash man page too, huh?
guns
You better believe it! I do this sort of stuff all the time.
Mr. Muskrat
+2  A: 

These answers are correct for the cases they state but there is a still a problem if you run the script from another script using the 'source' keyword (so that it runs in the same shell). In this case, you get the $0 of the calling script. And in this case, I don't think it is possible to get the name of the script itself.

This is an edge case and should not be taken TOO seriously. If you run the script from another script directly (without 'source'), using $0 will work.

Jim Dodd
+1  A: 

With bash >= 3:

$ ./s
$0 is: ./s
$BASH_SOURCE is: ./s
$ . ./s
$0 is: bash
$BASH_SOURCE is: ./s

$ cat s
#!/bin/bash

printf '$0 is: %s\n$BASH_SOURCE is: %s\n' "$0" "$BASH_SOURCE
radoulov
Great! That's the answer which works for both ./scrip.sh and source ./script.sh
赵如飞
+3  A: 
# ------------- SCRIPT ------------- #

#!/bin/bash

echo
echo "# arguments called with ---->  ${@}     "
echo "# \$1 ---------------------->  $1       "
echo "# \$2 ---------------------->  $2       "
echo "# path to me --------------->  ${0}     "
echo "# parent path -------------->  ${0%/*}  "
echo "# my name ------------------>  ${0##*/} "
echo
exit

# ------------- CALLED ------------- #

# Notice on the next line, the first argument is called within double, 
# and single quotes, since it contains two words

$  /misc/shell_scripts/check_root/show_parms.sh "'hello there'" "'william'"

# ------------- RESULTS ------------- #

# arguments called with --->  'hello there' 'william'
# $1 ---------------------->  'hello there'
# $2 ---------------------->  'william'
# path to me -------------->  /misc/shell_scripts/check_root/show_parms.sh
# parent path ------------->  /misc/shell_scripts/check_root
# my name ----------------->  show_parms.sh

# ------------- END ------------- #
Bill Hernandez
That's unbelievable simple!
zzeroo
A: 

Re: Tanktalus's (accepted) answer above, a slightly cleaner way is to use:

me=$(readlink --canonicalize --no-newline $0)

If your script has been sourced from another bash script, you can use:

me=$(readlink --canonicalize --no-newline $BASH_SOURCE)

I agree that it would be confusing to dereference symlinks if your objective is to provide feedback to the user, but there are occasions when you do need to get the canonical name to a script or other file, and this is the best way, imo.

simon
Nice details, thanks.
Ma99uS