`find .` 和 /home/user/* 作为 for 命令的输入有什么区别

`find .` 和 /home/user/* 作为 for 命令的输入有什么区别

find ./home/user/*作为命令输入有什么区别for?例如:

for var in $(find .)
do echo "$var"
done

或者

for var in /home/user/*
do
echo "$var"
done

在第一种情况下,for命令会分解名称包含空格的文件。而在第二种情况下则不然。为什么?

答案1

这是 shell 的标准做法。操作的顺序是命令替换 ( $(find .)),然后分词,然后全局扩展 ( /home/user/*)。

来自POSIX标准(单词分割 = 字段分割;全局扩展 = 路径名扩展):

单词扩展的顺序如下:

  1. 应从头到尾执行波形符扩展(请参阅波形符扩展)、参数扩展(请参阅参数扩展)、命令替换(请参阅命令替换)和算术扩展(请参阅算术扩展)。请参阅令牌识别中的第 5 项。

  2. 除非 IFS 为空,否则应对步骤 1 生成的字段部分执行字段拆分(请参阅字段拆分)。

  3. 除非 set -f 有效,否则应执行路径名扩展(请参阅路径名扩展)。

  4. 报价删除(请参阅报价删除)应始终最后执行。


因此,始终建议尽可能使用 glob,以便分词不会干扰您的文件名。该$(find)构造实际上是一个示例Bash 陷阱 #1

答案2

shell 按顺序做事。 $(find .)称为命令替换。命令替换的结果受:

  1. 分词,
  2. 路径名扩展
  3. 报价删除

当文件名带有空格时,分词是导致问题的原因。

/home/user/*是路径名扩展。请注意,这是上面列表中的倒数第二个。它仅受报价删除的影响。

答案3

两者之间的另一个区别是 shell glob(如/home/user/*)通常不包含“隐藏文件”(以点开头的文件名)。另一方面,find将匹配除特殊目录“.”之外的所有文件名。和“..”(当前目录和父目录)。

答案4

解释它的另一种方法:当*使用时,shell 知道单个元素是什么。输出find只是一个长字符串。 shell 不知道元素(及其分隔符)是什么。

命令替换可以以特殊方式与产生带引号的输出的程序一起使用;那么问题就不会出现。但是为了使 shell 识别您需要的引用,例如,eval这通常会使整个表达式变得更加复杂:

eval for var in $(ls --quoting-style=shell)\; do echo '"$var"'\; done

相关内容