Por que preciso usar o CD "$ @" em vez do CD "$ 1" ao escrever um wrapper para CD?

25

Em outros lugares, vi uma função cd como abaixo:

cd()
{
 builtin cd "$@"
}

por que é recomendado usar em $@vez de $1?

Eu criei um diretório de teste "r st" e chamei o script que contém esta função e funcionou de qualquer maneira

$ . cdtest.sh "r st"

mas $ . cdtest.sh r stfalhei se eu usei "$@"ou"$1"

Ravi Kumar
fonte
11
cd "$*"também não funcionará corretamente com mais de 1 argumento.
GoFundMonica - codidact.org 25/10

Respostas:

57

Porque, de acordo com bash(1), cdleva argumentos

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

portanto, o diretório realmente pode não estar, $1pois isso poderia ser uma opção como -Loutra bandeira.

Quão ruim é isso?

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

As coisas podem dar errado se você não chegar onde espera usar cd "$1"

agitar
fonte
19

O uso "$@"passará todos os argumentos para cdonde como $1passará apenas o primeiro argumento.

Nos seus exemplos

$ . cdtest.sh "r st"

sempre funciona como você passa apenas em um argumento, mas se você passar uma bandeira também, como

$ . cdtest.sh -L "r st"

"$@"será executado corretamente onde "$1"será expandido, cd -Lperdendo o diretório completamente.

Contudo

$ . cdtest.sh r st

Falha nos dois casos, pois você está passando dois parâmetros para o cd re stnão é uma maneira válida de executar o cd. Os parâmetros são separados por espaços que devem ser citados (como no seu primeiro exemplo) ou escapados ( r\ st) para serem tratados como um argumento.

No caso do cd, no entanto, é muito incomum passar sinalizadores e você não pode passar em vários diretórios; portanto, você não verá a diferença no uso no mundo real de um "$1"ou "$@"de outro. Mas para outros comandos que você vai notar uma diferença, por isso é melhor prática para usar sempre "$@"quando você quer criar uma função wrapper ou script como este.

Michael Daffin
fonte
14

Também existe o caso em que não argumentos:

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

cdsem nenhum argumento muda para o diretório inicial. Sem argumentos, não se "$@"expande para nada, mas se "$1"expande para a cadeia vazia. Estes são diferentes:

$ args() { for i in "$@"; do echo "|$i|"; done; }
$ args
$ args ""
||
muru
fonte
Um pouco sem relação, mas: finalmente entendo por que um argumento nulo cdé uma coisa boa. Causa um erro em vez de mudar para o diretório inicial. Com alguns outros comandos, notavelmente rsync, um primeiro argumento nulo causa comportamento inesperado (inclui o diretório atual nas fontes da transferência).
Joe
4

Os argumentos para um script bash são delimitados por espaço. $ 1 é o primeiro argumento. Nos seus exemplos ...

No exemplo 1, $ 1 é a sequência "r st" ... no segundo exemplo, $ 1 é a sequência de um caractere 'r' ...

$ @ são todos os argumentos.

Carimbo de borracha
fonte