PDA

View Full Version : Can a Bash script determine where it is?


cwtnospam
06-16-2007, 09:05 AM
Just trying to teach myself some more Unix, so what I'm trying to do is simulate this Applescript with a shellscript:
on adding folder items to this_folder after receiving added_items
tell application "Finder"
repeat with aItem in added_items
if modification date of aItem < (current date) then
set x to POSIX path of aItem
set y to "touch -m " & x
do shell script y
end if
end repeat
end tell
end adding folder items to

Here's what I have:

#!/bin/bash
a=~
f=$a"/desktop/downloads"
c=$f"/.update.txt"
d=$f"/.update2.txt"
g=$f"/.list1"
h=$f"/.list"
touch -m $h
ls $f > $g
diff $h $g | grep ">" > $c
sed -e 's_>\ _'"$f/"'_g' $c > $d
cp $g $h
sed -e 's/\ /\\\ /g' $d | xargs touch -m
I'd like to replace $f with the path of the script, which would be placed in the folder it is watching.

hayne
06-16-2007, 09:26 AM
I'd like to replace $f with the path of the script, which would be placed in the folder it is watching.

The variable $0 contains the full path of the script being executed.

cwtnospam
06-16-2007, 10:00 AM
<smacks head!>I had checked $1 through $9 :o

cwtnospam
06-16-2007, 10:30 AM
Ok, is this the best way to remove the name and extension of the file 'testshell.sh' from $0?

t="/tmp/t"
echo $0 > $t
f=`sed -e 's_testshell.sh__g' $t`


Can I get $f directly from $0 without using a temp file? I tried using "$0" but that didn't work.

:o :o :o :o
EDIT: Never mind:
f=`dirname $0`

acr4
06-16-2007, 10:31 AM
#! /bin/bash
f=$(pwd) # 'pwd' is "present working directory"
#all of your code here

cwtnospam
06-16-2007, 10:51 AM
Odd that I didn't see your post even when I posted my edit, but you were 8 minutes before me!

Anyway, pwd returned '/etc' instead of the directory the script is located in.

biovizier
06-16-2007, 11:09 AM
How about something along the lines of:f=`dirname "$0"`

acr4
06-16-2007, 11:57 AM
Odd that I didn't see your post even when I posted my edit, but you were 8 minutes before me!

Anyway, pwd returned '/etc' instead of the directory the script is located in.

Yeah you're right. Looks like 'pwd' returns the calling path. I.e. if you are in /etc, and you call /home/my.script, 'pwd' in the script will return /etc (or so I gather).

Anyway looks like the $0 method is the best bet.

Hal Itosis
06-16-2007, 03:49 PM
How about something along the lines of:f=`dirname "$0"`
Those "lines" would be the fewest. ;)

cwtnospam
06-16-2007, 03:53 PM
I used f=`dirname $0` without the double quotes. Do those do anything in this case?

ataraxia
06-16-2007, 07:24 PM
$0 only has the name of the script as you ran it. So, it only has the full path if that's the way you ran it. If you just used the short name you won't be able to get the full name while the script is running.

Hal Itosis
06-17-2007, 03:40 PM
$0 only has the name of the script as you ran it. So, it only has the full path if that's the way you ran it. If you just used the short name you won't be able to get the full name while the script is running.

You would need to bypass the $PATH mechanism
by typing "./scriptname" while inside the parent
(or by typing whatever relative path necessary).

So, just typing "scriptname" will typically produce
the full path (as it gets looked up in the $PATH).

-HI-

Hal Itosis
06-17-2007, 04:02 PM
I used f=`dirname $0` without the double quotes. Do those do anything in this case?

If it happened (which isn't often, I admit) that the script had
a space (or spaces) in its name... the results would be wrong.

If this is a script named "two words"...

#!/bin/bash -
PATH='/bin:/usr/bin'
export PATH
IFS=$' \t\n'

echo `basename $0`
echo `dirname $0`
exit

...then, here is the result:

$ two\ words
two
usage: dirname path
$

The "two" is the unnoticed error from basename.
(The other is obvious).

Add quotes around "$0" to get it working.

-HI-

Acidprime
07-08-2007, 03:38 PM
declare -x SCRIPTPATH="${0}"
declare -x RUNDIRECTORY="${0%%/*}"
declare -x SCRIPTNAME="${0##*/}"

bwiese
11-28-2007, 08:43 AM
How to find and test the full path of the bash script being executed??? ....

I have not seen an answer to this posted anywhere else online and google brings up this page towards the top of a search, so I thought I better add this for prosperity:

myfp=`which $0`
mydir=`dirname $myfp`

Yes, the "which" command holds the key! :) Also, you can test that a string is a full path by testing if the first character is a "/" or not (on unix) with a test like...

if [ "/" == "${mydir:0:1}" ]; then
echo "full path = $mydir"
fi

I like working with full paths for all of my filesystem work... makes debugging easier at least!

apokalyptik
03-02-2008, 09:59 PM
The most reliable indicator of this attribute that I have found is to use LSOF. I tend to care about this on Linux and not OSX, but since this is very high in the google rankings for a search on "bash full path to file" I'm posting it here.

#!/bin/bash
## Linux
LSOF=$(lsof -p $$ | grep -E "/"$(basename $0)"$")
MY_PATH=$(echo $LSOF | sed -r s/'^([^\/]+)\/'/'\/'/1 2>/dev/null)
if [ $? -ne 0 ]; then
## OSX
MY_PATH=$(echo $LSOF | sed -E s/'^([^\/]+)\/'/'\/'/1 2>/dev/null)
fi

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"

.oO(apokalyptik@apok-mbp-en.lan ~) uname -a
Darwin apok-mbp-en.lan 9.2.0 Darwin Kernel Version 9.2.0: Tue Feb 5 16:13:22 PST 2008; root:xnu-1228.3.13~1/RELEASE_I386 i386 i386
.oO(apokalyptik@apok-mbp-en.lan ~) ./foo.sh
PATH /Users/apokalyptik/foo.sh
FILE foo.sh
CWD /Users/apokalyptik
PID 16347

Abu
09-10-2008, 01:58 PM
Try this one:

dir=$(dirname $(which $0));

hayne
09-20-2008, 10:35 AM
Use of the 'which' command in this context is not useful.
The 'which' command merely looks in the PATH and tells you which version of the command (given as an arg) is first in the PATH.

If you ran a script via its full pathname (e.g. /Users/Scripts/foo) then the PATH is irrelevant and so the result of using the 'which' command (as some people have suggested above) can be misleading (e.g. if the PATH does not include /User/Scripts in the above example).

chriswaco
11-14-2008, 08:57 AM
You can't use $0 because that gives only a relative path if the script is run with a command like ./myscript.sh.

The method below works well for both Linux and Mac OS X. It's a bit weird, but works.

#!/bin/bash
#==========================
# bash - find path to script
#==========================
abspath=$(cd ${0%/*} && echo $PWD/${0##*/})

# to get the path only - not the script name - add
path_only=`dirname "$abspath"`

#display the paths to prove it works
echo $abspath
echo $path_only

LN2
03-12-2009, 11:44 PM
I would change the line from the previous post:

abspath=$(cd ${0%/*} && echo $PWD/${0##*/})


to


abspath="$(cd "${0%/*}" 2>/dev/null; echo "$PWD"/"${0##*/}")"


This covers the case if the script was started with something like "bash yourscript.sh", which otherwise gives an error. It also adds some Quotes just to be on the save side if your $PWD contains /newlines or other 'ugly' characters.

Personally I prefer this method compared to the ones, that rely on "lsof -p" or "readlink -f", since it will probably work in a bash shell on almost any platform.

doubi
06-27-2009, 04:47 PM
I have a further requirement. The last few scripts suggested do indeed give the location of the script as it runs.

However if you source the script instead of running it, this gives the current working directory from which you called the script, not the directory in which the script itself resides.

Here's the scenario: I have a number of slightly different versions of a project in different folders in my home directory, which I want to compile intermittently. Each version contains certain libraries and output folders which have been hard-coded into the build process (not by me) to be located using environment variables. What I want is to be able to have the same script sit in the top level folder of each of these different project versions, set the relevant paths for that version, relative to that top directory, and add them to the environment before I go to build. Ya dig?

Given that I need to source the script instead of having it run in its own execution environment, it seems as if the solutions suggested here fall just short of sufficient (although they are as thorough as any I have seen on this topic).

Any further ideas would be gratefully received :-)

Hal Itosis
06-28-2009, 01:53 PM
New problem, new thread.