为什么 bash 在与 xargs 命令一起使用时不解释星号字符?

为什么 bash 在与 xargs 命令一起使用时不解释星号字符?

据我了解,星号字符*在 Bash 中具有特殊含义,为了打印文字字符,我们需要转义它 ( \*) 或引用它 ("*"'*'.

但是,当我尝试过以下操作时:

$ seq 3 |  xargs -I *  echo *
1
2
3

*为什么 Bash在上面的例子中不解释?但在下面的示例中,它确实将其解释为通配符(它与当前目录中的文件匹配):

$ seq 3 |  xargs -I*  echo * # no space between -I and *
main.py
main.py
main.py

您能解释一下这背后的逻辑吗?

谢谢

答案1

重击做过展开第一个示例中的星号。

假设当前目录仅包含一个文件 ,main.py则发生的情况如下:

$ seq 3 | xargs -I *  echo *
# Expands to:
$ seq 3 | xargs -I main.py echo main.py

echo main.py这要求对每个输入执行操作,并替换main.py为该输入(因为-I main.py)。这就是您所观察到的:三个模板从echo main.py变为echo 1, echo 2, echo 3

在第二种情况下,星号就在旁边,以-I防止该单词扩展(因为没有文件与模式匹配-I*):

$ seq 3 | xargs -I*  echo *
# Expands to:
$ seq 3 | xargs -I* echo main.py

这要求 xargs 用输入替换*模板中的(字面星号)的实例。echo main.py由于模板*根本不包含占位符,因此main.py每次都会打印。

failglob在 Bash 中启用或在 zsh 中使用默认设置时,不匹配任何内容的 glob 将产生错误,并且该命令将不会运行。)

如果您的命令保护了两次出现的*,那么您将获得与第一次尝试相同的输出:

$ seq 3 | xargs -I '*' echo '*'
1
2
3

如果目录中碰巧有多个文件,那么未加引号的文件*可能会产生更明显的问题。例如,如果有两个文件main.pyother.py,则:

$ seq 3 | xargs -I *  echo *
# Expands to:
$ seq 3 | xargs -I main.py other.py echo main.py other.py

并将尝试作为命令xargs运行(由当前输入字符串替换)。这可能会给出“命令未找到”错误。或者,如果排序顺序中的第二个文件名与 中的可运行程序匹配,则将运行other.py echo main.py other.pymain.pyxargsPATHxargs那个程序, 并不是echo


获得 Bash 扩展发生情况的一定程度可见性的一个有用技巧是运行set -o xtrace。设置标志后,您可以看到以 开头的行的扩展+

$ set -o xtrace
$ seq 3 | xargs -I * echo *
+ seq 3
+ xargs -I main.py echo main.py
1
2
3

$ seq 3 | xargs -I* echo *
+ seq 3
+ xargs '-I*' echo main.py
main.py
main.py
main.py

$ seq 3 | xargs -I '*' echo '*'
+ seq 3
+ xargs -I '*' echo '*'
1
2
3

相关内容