Почему при написании оболочки для cd мне нужно использовать cd «$ @» вместо cd «$ 1»?

25

В другом месте я видел функцию CD, как показано ниже:

cd()
{
 builtin cd "$@"
}

почему рекомендуется использовать $@вместо $1?

Я создал тестовый каталог "r st" и вызвал скрипт, содержащий эту функцию, и он работал в любом случае

$ . cdtest.sh "r st"

но $ . cdtest.sh r stне удалось, использовал ли я "$@"или"$1"

Рави Кумар
источник
1
cd "$*"также не будет работать правильно с более чем 1 аргументом.
GoFundMonica - codidact.org

Ответы:

57

Потому что, согласно bash(1), cdпринимает аргументы

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

поэтому, следовательно, каталог на самом деле может не быть, так $1как вместо этого может быть опция, такая как -Lили другой флаг.

Насколько это плохо?

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

Все может пойти очень плохо, если вы окажетесь не там, где вы ожидаете, используя cd "$1"...

thrig
источник
19

Использование "$@"передаст все аргументы туда, cdгде $1будет передаваться только первый аргумент.

В твоих примерах

$ . cdtest.sh "r st"

всегда работает, когда вы передаете только один аргумент, но если вы должны передать флаг, такой как

$ . cdtest.sh -L "r st"

Только "$@"тогда правильно выполнится, где "$1"расширится до cd -Lполной потери каталога.

тем не мение

$ . cdtest.sh r st

Сбой в обоих случаях, так как вы передаете два параметра в cd, rи stэто не является допустимым способом выполнения cd. Параметры разделяются пробелами, которые должны быть заключены в кавычки (как в первом примере) или экранированы ( r\ st), чтобы рассматриваться как один аргумент.

В случае компакт - диска , однако очень редко проходить в флажками , и вы не можете передать в нескольких каталогах , так что вы не будете видеть разницу в реальном мире использование либо "$1"или "$@"для компакт - диска. Но для других команд , которые вы будете замечать разницу , так что лучше практика , чтобы всегда использовать , "$@"когда вы хотите создать функцию - оболочку или сценарий , как это.

Майкл Даффин
источник
14

Также есть случай, когда нет аргументов:

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

cdбез каких-либо аргументов изменения в домашнем каталоге. Без каких-либо аргументов "$@"расширяется до нуля, но "$1"расширяется до пустой строки. Это разные:

$ args() { for i in "$@"; do echo "|$i|"; done; }
$ args
$ args ""
||
Мур
источник
Несколько не связано, но: я наконец понимаю, почему нулевой аргумент cd- это хорошо. Это вызывает ошибку вместо перехода в домашний каталог. С некоторыми другими командами, в частности rsync, нулевой первый аргумент вызывает непредвиденное поведение (включает текущий каталог в источниках передачи).
Джо
4

Аргументы скрипта bash разделены пробелом. $ 1 является первым аргументом. В твоих примерах ...

В примере 1 $ 1 - это строка «r st» ... во втором примере $ 1 - это строка из одного символа «r» ...

$ @ - это все аргументы.

Штамп
источник