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


25

在其他地方,我看到了cd功能,如下所示:

cd()
{
 builtin cd "$@"
}

为什么建议使用$@代替$1

我创建了一个测试目录“ r st”,并调用了包含此功能的脚本,无论哪种方式都可以工作

$ . cdtest.sh "r st"

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


1
cd "$*"也不能正常使用超过1个arg。
GoFundMonica-codidact.org

Answers:


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"


19

使用"$@"会将所有参数传递到cd,而$1只会传递第一个参数。

在你的例子中

$ . cdtest.sh "r st"

总是有效,因为您只传递了一个参数,但是如果您也传递了一个标志,例如

$ . cdtest.sh -L "r st"

然后只有"$@"正确执行"$1"才能扩展到cd -L完全丢失目录的位置。

然而

$ . cdtest.sh r st

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

但是,在cd的情况下,传递标志非常少见,并且您不能传递多个目录,因此您不会看到cd "$1""$@"cd 在实际使用中的区别。但是对于其他命令,您会发现有所不同,因此最好"$@"在要创建这样的包装函数或脚本时始终使用。


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 ""
||

有点无关,但是:我终于明白了,为什么对null的参数cd是一件好事。它将导致错误,而不是切换到主目录。值得注意的是rsync,对于其他一些命令,空的第一个参数会导致意外的行为(在传输源中包括当前目录)。

4

bash脚本的参数以空格分隔。$ 1是第一个参数。在您的示例中...

在示例1中,$ 1是字符串“ r st” ...在第二个示例中,$ 1是一个字符串'r'...

$ @是所有参数。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.