How can I find out the path of the directory in which my bash shell script is located and store that path in _base variable?

You need to use the combination of the following: [a] readlink – Display value of a symbolic link or canonical file name.
Tutorial details
Difficulty level Easy
Root privileges No
Requirements Unix like+
bash
Est. reading time N/A
This is a safe way to get the target of a symbolic link. [b] ${BASH_SOURCE[0]} or $0 – The name of the shell script file is stored in $0 or ${BASH_SOURCE[0]}

Please note that the following examples are only tested on the Bash shell running on Debian Linux. This code may not be portable and may break on other Linux distributions/Unix like operating systems.

Examples

Create a shell script as follows:

#!/bin/bash
# Name: /tmp/demo.bash : 
# Purpose: Tell in what directory $0 is stored in
# Warning: Not tested for portability 
# ------------------------------------------------
 
## who am i? ##
_script="$(readlink -f ${BASH_SOURCE[0]})"
 
## Delete last component from $_script ##
_base="$(dirname $_script)"
 
## Okay, print it ##
echo "Script name : $_script"
echo "Current working dir : $PWD"
echo "Script location path (dir) : $_base"

Save and close the file. Run it as follows:
$ chmod +x /tmp/demo.bash
$ /tmp/demo.bash

Sample outputs:

Script name : /tmp/demo.bash
Current working dir : /home/vivek
Script location path (dir) : /tmp

cd to /home/vivek
$ cd ~
$ /tmp/demo.bash

Sample outputs:

Script name : /tmp/demo.bash
Current working dir : /home/vivek
Script location path (dir) : /tmp

Run it as follows:
$ ../../tmp/demo.bash
Sample outputs:

Script name : /tmp/demo.bash
Current working dir : /home/vivek
Script location path (dir) : /tmp

Finally, create a symbolic link in /home/vivek and test it:
$ cd ~
$ ln -s /tmp/demo.bash
$ ./demo.bash
$ rm demo.bash

Sample outputs:

Script name : /tmp/demo.bash
Current working dir : /home/vivek
Script location path (dir) : /tmp

Know a better way to solve this problem? Add in the comments below.


🐧 Get the latest tutorials on Linux, Open Source & DevOps via RSS feed or Weekly email newsletter.

🐧 9 comments so far... add one


CategoryList of Unix and Linux commands
Disk space analyzersdf duf ncdu pydf
File Managementcat cp mkdir tree
FirewallAlpine Awall CentOS 8 OpenSUSE RHEL 8 Ubuntu 16.04 Ubuntu 18.04 Ubuntu 20.04
Modern utilitiesbat exa
Network UtilitiesNetHogs dig host ip nmap
OpenVPNCentOS 7 CentOS 8 Debian 10 Debian 8/9 Ubuntu 18.04 Ubuntu 20.04
Package Managerapk apt
Processes Managementbg chroot cron disown fg glances gtop jobs killall kill pidof pstree pwdx time vtop
Searchingag grep whereis which
User Informationgroups id lastcomm last lid/libuser-lid logname members users whoami who w
WireGuard VPNAlpine CentOS 8 Debian 10 Firewall Ubuntu 20.04
9 comments… add one
  • Nikesh Dec 11, 2012 @ 13:23

    # Dir in which bash script is
    echo `pwd`

    # name of bash script file
    echo `$0

    • kustodian Dec 11, 2012 @ 19:51

      echo `pwd` is not the directory in which the script is located in, but the current working directory, and echo $0 will not the print the name of the script, but the name of the command that is called. For example if the script is located in /home/username/my_script.sh and it contains:

      echo `pwd`
      echo $0

      then if you run the following commands:

      cd /tmp
      /home/username/my_script.sh

      the script will print:

      /tmp
      /home/username/my_script.sh
      

      and we want to print the dir of the script (/home/username), and the name of the script (my_script.sh).

      I would just like to confirm that readlink -f works for me on both Centos 5 and 6.

  • Andy Dec 11, 2012 @ 13:41

    I tend to use

    _base=$(cd $(dirname $0); pwd -P)
    • 🐧 nixCraft Dec 11, 2012 @ 13:53

      Nice one liner. But, it will fail with softlink (see the last example ln -s).

  • Shantanu Gadgil Dec 12, 2012 @ 6:34

    A couple of recommended optimizations (Linux only)
    * use ‘readlink -m’ instead of ‘readlink -f’
    * avoid using ‘dirname’, use bash’s internal ‘string cut’ functionality

    Cheers,
    Shantanu

    • kustodian Dec 12, 2012 @ 23:47

      Why is ‘readlink -m’ better than -f?

      What do you mean buy bash’s internal ‘string cut’? Do you mean this:

      echo ${0##*/}
  • Jared Dec 13, 2012 @ 9:05

    Here’s one excerpted from a functions file, and modified to standalone.
    It works in ksh and bash, don’t know about other shells.

    ts20 > cat functions.sh/fqn.sh

    function getScriptPath {
    typeset SCRIPT=$1
    STAT_RESULT=$(stat –format=%N $SCRIPT | sed -e “s/[\`’]//g”)

    if [ -L “$SCRIPT” ]; then
    STAT_RESULT=$(echo $STAT_RESULT | awk ‘{ print $3 }’)
    fi

    echo $STAT_RESULT

    echo $(getScriptPath $0)

    ts20 > functions.sh/fqn.sh
    functions.sh/fqn.sh

    ts20 > ln -s /home/jkstill/shell/functions.sh/fqn.sh /tmp

    ts20 > /tmp/fqn.sh
    /home/jkstill/shell/functions.sh/fqn.sh

  • hamis jumanne Apr 22, 2014 @ 11:35

    please help me on this how can i locate a file in any subdirectories , give its details, and show the path of its existence

  • Johny Why May 12, 2015 @ 6:20

    this works great for me:
    `dirname $0`
    love the brevity. any caution against using this form?
    i believe $0 does not work as expected if sourcing a file, but i know of no other problem with this form.

    thx!

Leave a Reply

Your email address will not be published.

Use HTML <pre>...</pre> for code samples. Still have questions? Post it on our forum