Tuesday, March 22, 2011

How a Bash Script Can Know Where It Is

A colleague of mine wrote a shell script that is called from various other scripts, from different locations. He wanted his script to be able to discover the directory at which it is stored, but didn't know how; of course, calling pwd inside the script would yield the current working directory (by default, the directory from which the original script was called), not the script's directory.

After a little googling, I found this solution by netizen apokalyptik:
#!/bin/bash
LSOF=$(lsof -p $$ | grep -E "/"$(basename $0)"$")
MY_PATH=$(echo $LSOF | sed -r s/'^([^\/]+)\/'/'\/'/1 2>/dev/null)

MY_PID=$$
MY_ROOT=$(dirname $MY_PATH)
MY_NAME=$(basename $0)

echo -e "PATH\t$MY_PATH"
echo -e "FILE\t$MY_NAME"
echo -e "CWD \t$MY_ROOT"
echo -e "PID \t$MY_PID"
The trick lies in the use of the lsof command, which returns a list of currently open files. From there, the script uses grep to locate the entry corresponding to the currently running script, sed to separate the full path from the entry, then basename & dirname to split the base directory and file name.

This solution could be further enhanced by adding the current user to the grep regular expression: as it is, it could return the path to a same-named file opened by another user – but unless you work on a multi-user environment, it shouldn't make much difference.