Bash script may need to get its own path. In normal Bash script, $0
is the path to the script. However, when a script is sourced, such as . a.sh
, a.sh
‘s $0
does not give a.sh
while the caller’s name. How to reliably get a bash script’s own path no matter whether the Bash script is executed or sourced is introduced in this post.
Short answer ∞
You can use ${BASH_SOURCE[0]}
to get the script’s own path, in sourced or directly executed Bash script.
Why ${BASH_SOURCE[0]}
contains the own path ∞
From bash manual
:
BASH_SOURCE
An array variable whose members are the source filenames where the corresponding shell function names in the FUNCNAME array variable are defined. The shell function ${FUNCNAME[$i]} is defined in the file ${BASH_SOURCE[$i]} and called from ${BASH_SOURCE[$i+1]}.
What about ${BASH_SOURCE[0]
? This following example shows it well.
We have 2 Bash scripts: a.sh and b.sh which is sourced by a.sh and contains a function.
a.sh
#!/bin/bash echo "\$0: $0" echo ${FUNCNAME[0]} in ${BASH_SOURCE[0]} . ./b.sh
b.sh
#!/bin/bash echo "\$0: $0" echo ${FUNCNAME[0]} in ${BASH_SOURCE[0]} fun() { echo ${FUNCNAME[0]} in ${BASH_SOURCE[0]} echo $0 } fun
What happens if we run a.sh directly by sh a.sh
?
The result is as follows.
$0: a.sh main in a.sh $0: a.sh source in ./b.sh fun in ./b.sh a.sh
What about we source a.sh by . a.sh
instead of executing it? It gives
$0: bash source in a.sh $0: bash source in ./b.sh fun in ./b.sh bash
In summary, in sourced or directly executed bash script files, ${BASH_SOURCE[0]
contains the path of the bash source file and ${FUNCNAME[0]
contains “source” or “main”. So, ${BASH_SOURCE[0]}
gives you a reliable variable for the Bash script source file path no matter whether it is used inside of a function and no matter whether the script is directed executed or sourced.
//A c function to get your own executable’s execution directory.
// Sometimes you want to know the program source
#include
#include
#include
#include
#include
#ifndef MAX_PATH
#define MAX_PATH 256
#endif
static char * get_path_to_me(void);
static char *
get_path_to_me ()
{
static char buffer[MAX_PATH];
char *cp;
int len;
if ((len = readlink (“/proc/self/exe”, buffer, sizeof (buffer) – 1)) != -1)
{
buffer[len] = ‘\0′;
cp=strrchr(buffer,’/’);
*cp=’\0′;
fprintf (stderr, “\n%s version 0.9, date Compiled: %s, “, cp+1, __DATE__);
fprintf (stderr, “is executed from %s\n”, buffer); //program executes, dirname ok
*cp=’/’;
}
else
*buffer = ‘\0’;
return (buffer);
}
#if 0 // set to 1 to test as stand-alone, leave as 0 if you want to include this function in your code.
/**
* @brief main
* @param argc
* @param argv
* @return
*/
int
main (int argc, char *argv[])
{
char *pgm;
char *pgmx;
pgm = strdup (get_path_to_me ());
strcpy(buffer,pgm);
printf(“\nfull path = %s, directory=%s program=%s\n”,buffer,dirname(pgm),basename(pgm));
return 0;
}
#endif
Thanks for sharing the C code.
This is a nice trick:
readlink (“/proc/self/exe”, buffer, sizeof (buffer) – 1)
This is awesome.
I still don’t completely understand it,
but I definitely understand it better than before
and I have a lot to learn about bash fundamentals anyway.
Thanks for the write-up!
Glad to know this post is useful.