为什么在调用此 Bash 脚本时文件参数需要引号?

gor*_*vix 13 bash shell-script

我对 Bash 脚本很陌生。我有一个“测试脚本”,我将其用作更高级/有用的脚本的基础:

#!/bin/bash
files=$1
for a in $files
do
    echo "$a"
done
Run Code Online (Sandbox Code Playgroud)

当我在没有任何引号的情况下调用它时,它只会在目录中选取一个文件:

testscript *.txt
Run Code Online (Sandbox Code Playgroud)

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

testscript '*.txt'
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?

Ste*_*ris 29

当你调用一个程序时

testscript *.txt
Run Code Online (Sandbox Code Playgroud)

然后你的shell进行扩展并计算出所有值。所以它可能会有效地将您的程序称为

testscript file1.txt file2.txt file3.txt file4.txt
Run Code Online (Sandbox Code Playgroud)

现在你的程序只看$1,所以只适用于file1.txt.

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

通常你会在这样的脚本中使用"$@"and $1

对于来自 CMD 脚本的人来说,这是一个“陷阱”,其中命令 shell 不执行globbing(众所周知)并且总是传递文字字符串。

  • 只是为了澄清(对于上述答案的作者以外的人),使用 `"$@"`(而不是 `$@` 或 `$1` `$2` `$3`)将导致每个文件名被引用 ` "file1.txt"` `"file2.txt"` 等。对于 `file1.txt` 来说这是没有意义的,但是如果你有 `my file.txt`,引用是*关键的*,以防止 shell 解析把它分成两个文件名,一个名为“my”,一个名为“file.txt”。总是引用用户输入和全局扩展,以免有一天你非常不高兴。 (6认同)
  • 这不仅仅是理论上的 - Mac OS X 曾经附带一个更新脚本,该脚本没有正确引用参数并最终在某些情况下删除人们的硬盘驱动器。 (2认同)
  • @fluffy,你有相关链接吗? (2认同)

Eri*_*ouf 7

如果没有引号,shell*.txt在调用脚本之前会展开,因此$1只有第一个被展开的文件。所有txt文件都是当时脚本的参数(假设没有太多)。

使用引号将字符串传递而不扩展到脚本中,然后for按照您的希望进行扩展。