8

I have larger shell script which handles different things.

It will get it's own location by the following...

BASEDIR=`dirname $0`/..
BASEDIR=`(cd "$BASEDIR"; pwd)`

then BASEDIR will be used create other variables like

REPO="$BASEDIR"/repo

But the problem is that this shell script does not work if the path contains spaces where it is currently executed.

So the question is: Does exist a good solution to solve that problem ?

khmarbaise
  • 92,914
  • 28
  • 189
  • 235
  • This should be posix, cause it should run on as many unixes as possible...Here you can see the script which i mean (it's used as a template). http://svn.codehaus.org/mojo/trunk/mojo/appassembler/appassembler-maven-plugin/src/main/resources/org/codehaus/mojo/appassembler/daemon/script/unixBinTemplate – khmarbaise Dec 28 '11 at 17:04
  • I ran the commands above in both `bash` and `dash` (what Ubuntu uses for `sh`), in a directory whose parent directory's name has spaces. It appears to work just fine. What happens if you run the commands from a terminal in a problematic directory, followed by `echo "$REPO"` ? My guess is that you forgot to quote `"$REPO"` somewhere. – Joey Adams Dec 28 '11 at 17:24
  • Full0-quoting subshells is often what you want. Full quoting `$0` is certainly a good idea. A more complete example would be helpful. – sorpigal Dec 28 '11 at 19:43

7 Answers7

9

Be sure to double-quote anything that may contain spaces:

BASEDIR="`dirname $0`"
BASEDIR="`(cd \"$BASEDIR\"; pwd)`"
Fred Foo
  • 355,277
  • 75
  • 744
  • 836
7

The answer is "Quotes everywhere."

If the path you pass in has a space in it then dirname $0 will fail.

$ cat quote-test.sh
#!/bin/sh

test_dirname_noquote () {
        printf 'no quotes: '
        dirname $1
}
test_dirname_quote () {
        printf 'quotes: '
        dirname "$1"
}

test_dirname_noquote '/path/to/file with spaces/in.it'
test_dirname_quote '/path/to/file with spaces/in.it'

$ sh quote-test.sh
no quotes: usage: dirname string
quotes: /path/to/file with spaces

Also, try this fun example

#!/bin/sh

mkdir -p /tmp/foo/bar/baz
cd /tmp/foo
ln -s bar quux
cd quux
cat >>find-me.sh<<"."
#!/bin/sh

self_dir="$(dirname $0)"
base_dir="$( (cd "$self_dir/.." ; pwd -P) )"
repo="$base_dir/repo"

printf 'self: %s\n' "$self_dir"
printf 'base: %s\n' "$base_dir"
printf 'repo: %s\n' "$repo"
.

sh find-me.sh

rm -rf /tmp/foo

Result when you run it:

$ sh example.sh
self: .
base: /tmp/foo
repo: /tmp/foo/repo
sorpigal
  • 25,504
  • 8
  • 57
  • 75
2

Quote your full variable like this:

REPO="$BASEDIR/repo"
Marcus
  • 12,296
  • 5
  • 48
  • 66
sralmai
  • 197
  • 1
  • 5
2

There is no reliable and/or portable way to do this correctly.

See How do I determine the location of my script? as to why

The best answer is the following, which is still OS dependent

BASEDIR=$(readlink -f $0)

Then you can do things like REPO="$BASEDIR"/repo , just be sure to quote your variables as you did.

SiegeX
  • 135,741
  • 24
  • 144
  • 154
1

Works perfectly fine for me. How are you using REPO? What specifically "doesn't work" for you?

I tested

#!/bin/sh
BASEDIR=`dirname $0`/..
BASEDIR=`(cd "$BASEDIR"; pwd)`
REPO="$BASEDIR"/repo
echo $REPO

in a ".../a b/c d" directory. It outputs ".../a b/repo", as expected.

Please give the specific error that you are receiving... A "doesn't work" bug report is the least useful bug report, and every programmer absolutely hates it.

Amadan
  • 191,408
  • 23
  • 240
  • 301
1

Using spaces in directory names in unix is always an issue so if they can be avoided by using underscores, this prevents lots of strange scripting behaviour.

I'm unclear why you are setting BASEDIR to be the parent directory of the directory containing the current script (..) and then resetting it after changing into that directory

The path to the directory should still work if it has ..

e.g. /home/trevor/data/../repo

BASEDIR=`dirname $0`/..

I think if you echo out $REPO it should have the path correctly assigned because you used quotes when assigning it but if you then try to use $REPO somewhere else in the script, you will need to use double quotes around that too.

e.g.

#!/bin/ksh

BASEDIR=`dirname $0`/..
$REPO="$BASEDIR"/repo

if [ ! -d ["$REPO"] 
then
  echo "$REPO does not exist!"
fi
shellter
  • 36,525
  • 7
  • 83
  • 90
Trevor North
  • 2,286
  • 1
  • 16
  • 19
1

Use speech marks as below:

 BASEDIR=`dirname "${0}"`/..
Drona
  • 6,886
  • 1
  • 29
  • 35