为什么 `cat` 在这里列出文件而不是文件内容?

Why does `cat` list files instead of content of file here?

我今天尝试用 bash 脚本做一些棘手的事情,这让我质疑我对 bash 脚本的了解。

我有以下名为 get_ftypes.sh 的脚本,其中第一个输入参数是一个包含文件 globs:

的文件
for ftype in `cat `
do
    echo "this is ftype $ftype"
done

例如,脚本会这样调用 get_ftypes.sh file_typesfile_types 会包含这样的内容:

*.txt
*.sh

我希望 echo 打印文件中的每一行,在本例中为 *.txt*.sh 等。但是,它扩展了 globbing, *,它回显实际文件 names,而不是我期望的 globb。

这种行为有什么原因吗?我不知道为什么。谢谢。

在行 for ftype in `cat ` 上,shell 执行 分词 路径扩展 。如果您不想那样,请使用 while 循环:

while read -r ftype
do
    echo "this is ftype $ftype"
done <""

此循环一次从文件 </code> 中读取一行,并且在从每一行中删除前导和尾随空格的同时,不执行任何扩展。 (如果要保留前导和尾随空格,请使用 <code>while IFS= read -r ftype)。

通常,当您遍历已经是 shell 定义的变量的项目时,for 循环很有用,例如 for x in "$@"。如果您正在从外部命令或文件中读取内容,您通常需要一个 while read 循环。

替代方案不使用 shell

逐行处理文件时,通常可以使用 sed 或 awk 更有效地实现目标。作为使用 awk 的例子,上面的循环简化为:

$ awk '{print "this is ftype " [=11=]}' filetypes 
this is ftype *.txt
this is ftype *.sh
echo $(cat foo)

将生成 foo 的内容,将它们拆分为单词,对每个单词进行 globs - 即,将 foo 的内容视为参数 - 然后将其插入当前命令行。

echo "$(cat foo)"

会将 foo 的内容作为单个参数生成,不将它们视为参数,不会 glob(但你只会通过循环一次)。

您想一次阅读 foo 一行;为此使用 while read -r ftype