bash:为什么" for"读取数组时有不同的行为" $ {files [@]}"

时间:2017-10-25 04:23:43

标签: bash

我想逐行阅读文本文件,这里有两种方法:

这个方法工作正常,逐行读取文本,我知道它使用read命令

readarray -t files < c.txt

for i in "${files[@]}"; do  
    printf '%s\n' "$i" >> 2.txt
    read -p 'press enter to continue'
done

但是这个方法一次读取所有文件而不是逐行读取!

for i in "$(<c.txt)"; do 
    printf '%s\n' "$i" >> 1.txt
    read -p 'press enter to continue'
done

如果我删除"$(<c.txt)"中的双引号并使用IFS=$'\n'set -f,则会按预期逐行阅读文字。

问题: 为什么当我使用"${files[@]}"时,它逐行读取,为什么for有不同的行为?

此示例中使用的文本文件:

$ cat c.txt

this   is         a   test   
)=_ç)çà)èç(-è_-'é²"²2°4.²&é (§/%Mµ%µ¨£¨P£

    trailing space        



tab                
#comment
*
echo test    

1 个答案:

答案 0 :(得分:1)

使用for的问题在于它对行没有任何了解 - for期望得到一个“单词”列表来迭代。如果使用for i in "$(<c.txt)",则双引号会告诉shell不要对文件内容进行任何解析,因此整个内容将被视为单个单词。另一方面,如果你不使用双引号(for i in $(<c.txt)),shell会将文件内容拆分为由空格分隔的“单词”(默认情况下表示空格,制表符和换行符),然后尝试将包含通配符的任何单词扩展为匹配文件名列表。你可以调整shell选项,使这个拆分和扩展过程更像你想要的那样,但从根本上说它是为了做其他事情而且最多只是一个kluge。

如果要从文件中读取行,请使用用于从文件中读取行的内容。 readreadarray都是为此目的而设。有他们自己的怪癖,你可能需要解决,但他们至少从正确的区域开始; for确实没有。顺便说一下,BashFAQ entry you linked对于ffmpeg等问题有一个非常好的解决方法:

while read -r line <&3; do
    ...
done 3<file

您提供的readline方法也可以正常使用,但不是那么便携。 readline所做的是将整个文件读入一个shell数组,每行作为一个单独的数组元素。然后"${files[@]}"告诉shell扩展数组内容,每个数组元素都被视为一个单独的单词。因此,行成为数组元素,它们变成“单词”,这是for迭代的东西,并且你得到了预期的结果。