25

Elsewhere I have seen a cd function as below:

cd()
{
 builtin cd "$@"
}

why is it recommended to use $@ instead of $1?

I created a test directory "r st" and called the script containing this function and it worked either way

$ . cdtest.sh "r st"

but $ . cdtest.sh r st failed whether I used "$@" or "$1"

  • 1
    cd "$*" also wont work correctly with more than 1 arg. – Sampo Sarrala Oct 25 '17 at 20:42
57

Because, according to bash(1), cd takes arguments

   cd [-L|[-P [-e]] [-@]] [dir]
          Change  the  current  directory to dir.  if dir is not supplied,
          ...

so therefore the directory actually may not be in $1 as that could instead be an option such as -L or another flag.

How bad is this?

$ cd -L /var/tmp
$ pwd
/var/tmp
$ cd() { builtin cd "$1"; }
$ cd -L /var/tmp
$ pwd
/home/jhqdoe
$ 

Things could go very awry if you end up not where you expect using cd "$1"

18

Using "$@" will pass all arguments to cd where as $1 will only pass the first argument.

In your examples

$ . cdtest.sh "r st"

always works as you only pass in one argument, but if you were to pass in a flag as well such as

$ . cdtest.sh -L "r st"

Then only "$@" will execute correctly where "$1" will expand to cd -L losing the directory entirely.

However

$ . cdtest.sh r st

Fails in both cases as you are passing two parameters to cd, r and st which is not a valid way to execute cd. Parameters are separated by spaces which must be quoted (as in your first example) or escaped (r\ st) to be treated as one argument.

In the case of cd however it is very uncommon to pass in flags and you cannot pass in multiple directories so you will not see the difference in a real world use of either "$1" or "$@" for cd. But for other commands you will notice a difference so it is best practice to always use "$@" when you want to create a wrapper function or script like this.

14

There's also the case when there are no arguments:

$ cd /tmp; cd; pwd
/home/muru
$ cd_func() { builtin cd "$1"; }
$ cd_func /tmp; cd_func; pwd
/tmp

cd without any arguments changes to the home directory. Without any arguments, "$@" expands to nothing, but "$1" expands to the empty string. These are different:

$ args() { for i in "$@"; do echo "|$i|"; done; }
$ args
$ args ""
||
  • Somewhat unrelated, but: I finally understand why a null argument to cd is a good thing. It causes an error instead of changing to the home directory. With some other commands, notably rsync, a null first argument causes unexpected behavior (includes the current directory in the sources of the transfer). – Joe Oct 27 '17 at 20:23
4

Arguments to a bash script are space delimited. $1 is the first argument. In your examples...

In example 1, $1 is the string "r st" ... in the second example, $1 is the one character string 'r' ...

$@ is all the arguments.

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.