2

I am trying to write a simple shell script, which will change the directory to the shell script directory and echo it.

This is the script:

#!/bin/bash
# cd '/explicit/path/to/script'
cd $(dirname $0)
echo $(dirname $0)

The output indeed is always, even if I use an explicite cd to the script dir.

/bin

What am I missing?

  • How are you running the script? – Stephen Kitt May 24 '16 at 6:08
  • run it from within home dir: . /path/to/script.sh – Skip May 24 '16 at 6:10
  • 2
    you're sourcing the script, not executing it. $0 is probably /bin/bash (i.e. your current command-line shell) from the sourced script's POV. – cas May 24 '16 at 6:11
4

You need to run the script instead of sourcing it:

/path/to/script.sh

(without .).

When you run

. /path/to/script.sh

$0 is your current shell, which is presumably in /bin (hence the behaviour you're seeing). Note that it needn't be /bin/bash, the shebang doesn't have any effect when sourcing a script.

Lucas' other points are valid, you should use quotes and just run dirname directly, without echo.

  • If the OP wants to change to that directory, he may want to call the script with cd "$(/path/to/script)" - however, it must be executed instead of sourced; and an executed script runs in an own subshell and hence cannot change the directory of the calling shell. There are other approaches to do so better (aliases, functions, ...) – rexkogitans May 24 '16 at 11:21
3

The variable $0 points to the shell script that you execute itself. So if you have a file in that contains this

#!/bin/sh
echo "$0"

and copy it to /bin/my-script and to ~/somewhere/my-script-2, make both copies executable you can observe this behavior (I assume /bin is in your $PATH):

$ my-script
/bin/my-script
$ ~/somewhere/my-script-2
/home/luc/somewhere/my-script-2
$ cd
$ somewhere/my-script-2
somewhere/my-script-2
$ ../../bin/my-script
../../bin/my-script
$ cd /bin
$ ./my-script
./my-script

and so on.

In an interactive shell $0 points to the shell you execute and that is most probably in /bin. So if you source the above shell scripts you will always see the path to your shell interpreter: /bin/bash . For this the two script don't have to be executable:

$ . my-script
/bin/bash
$ . ~/somewhere/my-script-2
/bin/bash
$ cd
$ . somewhere/my-script-2
/bin/bash
$ . ../../bin/my-script
/bin/bash
$ cd /bin
$ . ./my-script
/bin/bash

The reason is that a sourced script is executed in the same process that sources it and $0 is not changed ($@ is updated though).

If dirname "$0" prints /bin for you, that just means the file you execute is in /bin or you are running dirname from a interactive session or a sourced script and the interpreter you use is in /bin.

Some other points:

  • You don't need to do echo "$(dirname "$0")", dirname "$0" will do the same.
  • Use pwd the get the current working directory.
  • Put quotes around $0 and command substitution as you might run into problems otherwise. Try something like cd $(echo a b c) to see the problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.