Por que eu preciso usar o cd “$ @” em vez do cd “$ 1” ao escrever um wrapper para cd?

24

Em outro lugar, vi uma função de 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 essa função e funcionou de qualquer maneira

$ . cdtest.sh "r st"

mas $ . cdtest.sh r st falhou ao usar "$@" ou "$1"

    
por Ravi Kumar 24.10.2017 / 23:53

4 respostas

55

Porque, de acordo com bash(1) , cd aceita argumentos

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

Portanto, o diretório, na verdade, pode não estar em $1 , já que poderia ser uma opção como -L ou outro sinalizador.

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 você espera usar cd "$1"

    
por 24.10.2017 / 23:56
18

Usar "$@" passará todos os argumentos para cd , em que $1 passará apenas o primeiro argumento.

Nos seus exemplos

$ . cdtest.sh "r st"

funciona sempre que você só passa em um argumento, mas se você fosse passar uma bandeira também, como

$ . cdtest.sh -L "r st"

Em seguida, somente "$@" será executado corretamente, onde "$1" será expandido para cd -L , perdendo completamente o diretório.

No entanto

$ . cdtest.sh r st

Falha nos dois casos quando você passa dois parâmetros para cd, r e st , o que não é uma maneira válida de executar o cd. Os parâmetros são separados por espaços que devem ser citados (como em seu primeiro exemplo) ou com escape ( r\ st ) para serem tratados como um argumento.

No caso de cd, no entanto, é muito incomum passar flags e você não pode passar em vários diretórios, assim você não verá a diferença no uso real de "$1" ou "$@" para cd. Mas para outros comandos você irá notar uma diferença, portanto, é uma prática recomendada usar sempre "$@" quando você quiser criar uma função de wrapper ou um script como este.

    
por 25.10.2017 / 00:04
14

Também há casos em que não há argumentos não :

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

cd sem quaisquer alterações de argumentos no diretório inicial. Sem nenhum argumento, "$@" se expande para nada, mas "$1" expande para a string vazia. Estes são diferentes:

$ args() { for i in "$@"; do echo "|$i|"; done; }
$ args
$ args ""
||
    
por 25.10.2017 / 03:50
4

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

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

$ @ é todos os argumentos.

    
por 25.10.2017 / 00:02