调用此Bash脚本时,为什么文件参数必须使用引号?


13

我对Bash脚本非常陌生。我有一个“ testscript”,它用作更高级/有用的脚本的基础:

#!/bin/bash
files=$1
for a in $files
do
    echo "$a"
done

当我不带引号的情况下调用它时,它只会在目录中拾取一个文件:

testscript *.txt

但是,当我用引号将其调用时,它可以正常工作并挑选出所有文本文件:

testscript '*.txt'

这里发生了什么?


要非常非常清楚地指出,解决此问题的正确方法是在脚本中运行for a in "$@"; do(或for a; do),从而将问题抛在了外壳上,而不是省略了引号。
查尔斯·达菲


这很值得一看。 guide.bash.academy
vascowhite

Answers:


29

调用程序时

testscript *.txt

然后您的shell进行扩展并计算出所有值。因此,它可以有效地将您的程序调用为

testscript file1.txt file2.txt file3.txt file4.txt

现在,您的程序只能查看,$1因此只能在上运行file1.txt

通过在命令行上引用,您可以将文字字符串传递*.txt给脚本,这就是存储在中的内容$1for然后,您的循环将其展开。

通常,您将使用"$@"而不是这样$1的脚本。

对于来自CMD脚本的人们来说,这是一个“陷阱”,在此命令外壳程序不进行globbing(众所周知),并且始终传递文字字符串。


6
只是为了澄清(对于上述答案的作者以外的其他人),使用"$@"(而不是$@$1 $2 $3)将导致每个文件名都被引用"file1.txt" "file2.txt"等等。file1.txt这是没有意义的,但是如果您使用my file.txt,则引用对于防止shell 至关重要。解析后将其转换为两个文件名,一个名为my,一个名为file.txt。始终引用用户输入和全局扩展,以免有一天您不满意。
塞斯·罗伯逊

2
这不仅仅是理论上的问题-Mac OS X曾经附带了一个更新脚本,该脚本没有正确地引用参数并最终在某些情况下删除了人们的硬盘。
蓬松的

2
@fluffy,您是否有相关链接?
2016年

@Wildcard不幸的是,我找不到任何有关它的文章,但是当它发生时,这在科技界是个大新闻。我想说的是在2003/2004左右,当时苹果仍然是成为UNIX发行商的主意。
蓬松的

1
@wildcard啊,找到了!xlr8yourmac.com/OSX/itunes2_erased_drives.html-实际上是iTunes升级脚本是罪魁祸首。
蓬松的

7

不带引号的外壳将*.txt在调用脚本之前扩展,因此$1只有第一个扩展的文件才会扩展。此时所有txt文件都是脚本的参数(假设没有太多)。

用引号将该字符串传递而无需扩展为脚本,然后可以for按照您的期望进行扩展。

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.