为什么在为 cd 编写包装器时需要使用 cd "$@" 而不是 cd "$1" ?

RKA*_*RKA 25 shell bash cd-command function arguments

在其他地方,我看到了一个 cd 函数,如下所示:

cd()
{
 builtin cd "$@"
}
Run Code Online (Sandbox Code Playgroud)

为什么建议使用$@而不是$1

我创建了一个测试目录“r st”并调用了包含这个函数的脚本,它以任何一种方式工作

$ . cdtest.sh "r st"
Run Code Online (Sandbox Code Playgroud)

$ . cdtest.sh r st无论我使用"$@"还是失败"$1"

thr*_*rig 57

因为,根据bash(1)cd需要参数

   cd [-L|[-P [-e]] [-@]] [dir]
          Change  the  current  directory to dir.  if dir is not supplied,
          ...
Run Code Online (Sandbox Code Playgroud)

因此,该目录实际上可能不在其中,$1因为它可能是一个选项,例如-L或其他标志。

这有多糟糕?

$ cd -L /var/tmp
$ pwd
/var/tmp
$ cd() { builtin cd "$1"; }
$ cd -L /var/tmp
$ pwd
/home/jhqdoe
$ 
Run Code Online (Sandbox Code Playgroud)

如果您最终不在您期望的地方使用,事情可能会变得很糟糕cd "$1"……


Mic*_*fin 19

Using"$@"会将所有参数传递给cdwhere as$1只会传递第一个参数。

在你的例子中

$ . cdtest.sh "r st"
Run Code Online (Sandbox Code Playgroud)

始终有效,因为您只传递一个参数,但是如果您还要传递一个标志,例如

$ . cdtest.sh -L "r st"
Run Code Online (Sandbox Code Playgroud)

然后只会"$@""$1"将扩展到cd -L完全丢失目录的地方正确执行。

然而

$ . cdtest.sh r st
Run Code Online (Sandbox Code Playgroud)

未能在这两种情况下,你是传递两个参数到CD,rst这是不执行CD的一种有效方式。参数由空格分隔,这些空格必须被引用(如在您的第一个示例中)或转义 ( r\ st) 才能被视为一个参数。

然而,在 cd 的情况下,传入标志是非常罕见的,并且您不能传入多个目录,因此您不会看到在现实世界中使用cd"$1""$@"cd的区别。但是对于其他命令,您注意到不同之处,因此"$@"当您想创建这样的包装函数或脚本时,最好始终使用它。


mur*_*uru 14

还有没有参数的情况:

$ cd /tmp; cd; pwd
/home/muru
$ cd_func() { builtin cd "$1"; }
$ cd_func /tmp; cd_func; pwd
/tmp
Run Code Online (Sandbox Code Playgroud)

cd没有任何参数更改主目录。没有任何参数,"$@"扩展为"$1"空,但扩展为空字符串。这些是不同的:

$ args() { for i in "$@"; do echo "|$i|"; done; }
$ args
$ args ""
||
Run Code Online (Sandbox Code Playgroud)