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

时间:2016-06-16 05:25:44

标签: bash macos shell glob

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

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

for ftype in `cat $1`
do
    echo "this is ftype $ftype"
done

例如,脚本将像get_ftypes.sh file_types一样被调用,而file_types将包含如下内容:

*.txt
*.sh

我希望echo打印文件中的每一行,在此示例中为*.txt*.sh等。但是,它会扩展globbing,{{ 1}},它回应实际的文件 名称 ,而不是我期望的globb。

出现这种行为的原因是什么?我无法弄清楚为什么。谢谢。

2 个答案:

答案 0 :(得分:3)

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

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

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

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

替代不使用shell

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

$ awk '{print "this is ftype " $0}' filetypes 
this is ftype *.txt
this is ftype *.sh

答案 1 :(得分:1)

echo $(cat foo)

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

echo "$(cat foo)"

会将foo的内容作为单个参数生成,不会将它们视为参数,也不会将其视为全局(但只能通过循环获得一次)。

您希望一次只读一行foo;请使用while read -r ftype