2

What is the best way to write a shell script that will access files relative to it such that it doesn't matter where I call it from? "Easy" means the easiest/recommended way that will work across different systems/shells.

Example

Say I have a folder ~/MyProject with subfolders scripts/ and files/. In scripts/, I have a shell script foo.sh that wants to access files in files/:

if [ -f "../files/somefile.ext" ]; then
    echo "File found"
else
    echo "File not found"
fi

It'll work fine If I do cd ~/MyProject/scripts && ./foo.sh, but it will fail with cd ~/MyProject && scripts/foo.sh.

Ingo Bürk
  • 19,263
  • 6
  • 66
  • 100
  • 1
    See if http://stackoverflow.com/questions/59895/can-a-bash-script-tell-what-directory-its-stored-in helps. – Ed Morton Aug 25 '13 at 01:24

6 Answers6

3

You can usually do:

mydir="$(dirname $0)"

to get the directory of the running script.

Then just use that to locate your files.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • That's the way I knew about so far. But other threads on SO suggest that this breaks in many cases (may it be different systems or different ways of calling the script, like sourcing it). – Ingo Bürk Aug 24 '13 at 22:24
  • Edit the question to add give such examples. Currently your question is too vague. (At least you should restrict the use to some extent. Too much generality can't do anything.) – teika kazura Aug 24 '13 at 23:41
1

Make all paths absolute. Use environmental variables when possible, for example $HOME. You are running into a weakness of UNIX scripting.

Using a .profile or .bash_profile, your developers could set a bunch of ENV variables. Then your scripts could make use of those variables.

In one of the places I worked, you could run a script, that would prompt you for which version you wanted to look at, and set the ENVs such that developer interaction was pretty seamless.

Pete B.
  • 3,188
  • 6
  • 25
  • 38
  • Say it's a script in a git repo. Anyone cloning it will have it in a different folder – how would I know any absolute paths? – Ingo Bürk Aug 24 '13 at 22:16
  • @Ingo: but how would the script know? Just make the work path an input parameter. – Vlad Aug 24 '13 at 22:31
  • "how would the script know?" – my point exactly :) I wish there'd just be an option for scripts so that the system treats it as if it was called from the directory it is in... – Ingo Bürk Aug 24 '13 at 22:33
  • 1
    You can use environmental variables as Pete mentioned above. Each user can set it to the correct path in his/her local computer (once). – MNZ Aug 24 '13 at 23:41
0

Not sure if it's easy enough for you but this could give you a solution:

Shell Script Loader

konsolebox
  • 72,135
  • 12
  • 99
  • 105
  • I'd rather not install additional stuff. I feel like it should be pretty basic to write shell scripts that can be called from anywhere, but maybe that's just wrong. – Ingo Bürk Aug 24 '13 at 22:26
  • @IngoBürk Well it's up to you :) I made the project after all because of that necessity. If the shells had provided a solution like that already it wouldn't have been necessary. You could make an embedded solution on your own similar to what I had but I would bet that the complexity would just be similar, unless you'd prefer to use hacks instead, which most of the time makes the script run terribly slow due to many subshell calls and call to external commands. Sometimes it also makes the script more confusing with respect to readability. Btw those are scripts too just in case you don't know. – konsolebox Aug 24 '13 at 22:41
0
if [ -f "../files/somefile.ext"]
then
  echo "file was found"
else
  echo "file was not found"
fi

second:

if [ ! -f /tmp/foo.txt ]; then
    echo "File not found!"
fi
ant
  • 54
  • 1
  • 9
0

Considering that $0 should contain the path to the executed script, you can simply cd to it and then process normally

So you simply do

scriptDir=$(dirname -- "$0")
cd -- "$scriptDir"

But that is still a hack, you probably should think of a way to work with absolute paths

Aleks-Daniel Jakimenko-A.
  • 10,335
  • 3
  • 41
  • 39
0

Unfortunately there doesn't seem to be a truly generic solution. My personal recommendation (and practice) is to write only for shells that provide consistent access to this--recent ksh93's ${.sh.file}, bash's $BASH_SOURCE, etc. (I don't know the zsh solution, but I'm sure there is one.)

Beyond that, the best solution is to avoid the problem in some way; e.g., for your example of a script in a git repository, you could require that the script be called from the directory it's in. After validating that by checking [[ -e myscript ]], you can then expect that relative links will work as expected. (Yes, for full robustness, you'll need to hardcode the basename of the script into the test, for the same reason this problem exists in the first place--it's available to the shell in all conceivable circumstances.)

Aaron Davies
  • 1,190
  • 1
  • 11
  • 17