我今天尝试用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。
出现这种行为的原因是什么?我无法弄清楚为什么。谢谢。
答案 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
循环。
逐行处理文件时,通常可以使用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
。