¿Por qué necesito usar el cd "$ @" en lugar del cd "$ 1" al escribir un contenedor para cd?

25

En otros lugares he visto una función de CD como se muestra a continuación:

cd()
{
 builtin cd "$@"
}

¿Por qué se recomienda usar en $@lugar de $1?

Creé un directorio de prueba "r st" y llamé al script que contiene esta función y funcionó de cualquier manera

$ . cdtest.sh "r st"

pero $ . cdtest.sh r stfalló si usé "$@"o"$1"

Ravi Kumar
fuente
1
cd "$*"tampoco funcionará correctamente con más de 1 arg.
GoFundMonica - codidact.org

Respuestas:

57

Porque, según bash(1), cdtoma argumentos

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

por lo tanto, el directorio en realidad puede no estar $1ya que podría ser una opción como -Lu otra bandera.

¿Qué tan malo es esto?

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

Las cosas podrían salir muy mal si no terminas donde esperas usar cd "$1"...

thrig
fuente
19

El uso "$@"pasará todos los argumentos a cddonde como $1solo pasará el primer argumento.

En tus ejemplos

$ . cdtest.sh "r st"

siempre funciona ya que solo pasa un argumento, pero si pasara una bandera también, como

$ . cdtest.sh -L "r st"

Entonces solo "$@"se ejecutará correctamente donde "$1"se expandirá a cd -Lperder el directorio por completo.

sin embargo

$ . cdtest.sh r st

Falla en ambos casos ya que está pasando dos parámetros a cd, ry stque no es una forma válida de ejecutar cd. Los parámetros están separados por espacios que deben citarse (como en su primer ejemplo) o escapar ( r\ st) para ser tratados como un argumento.

En el caso de cd, sin embargo, es muy raro pasar banderas y no puede pasar en múltiples directorios, por lo que no verá la diferencia en el uso en el mundo real de "$1"o "$@"para cd. Pero para otros comandos , notará una diferencia, por lo que es una buena práctica usar siempre "$@"que desee crear una función de envoltura o un script como este.

Michael Daffin
fuente
14

También está el caso cuando no hay argumentos:

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

cdsin ningún argumento cambia al directorio de inicio. Sin ningún argumento, se "$@"expande a nada, pero se "$1"expande a la cadena vacía. Estos son diferentes:

$ args() { for i in "$@"; do echo "|$i|"; done; }
$ args
$ args ""
||
muru
fuente
Algo no relacionado, pero: finalmente entiendo por qué un argumento nulo cdes bueno. Causa un error en lugar de cambiar al directorio de inicio. Con algunos otros comandos, en particular rsync, un primer argumento nulo provoca un comportamiento inesperado (incluye el directorio actual en las fuentes de la transferencia).
Joe
4

Los argumentos de un script bash están delimitados por espacios. $ 1 es el primer argumento. En tus ejemplos ...

En el ejemplo 1, $ 1 es la cadena "r st" ... en el segundo ejemplo, $ 1 es la cadena de caracteres 'r' ...

$ @ es todos los argumentos.

Sello de goma
fuente