Em:
cat test.txt | while read i; do echo $i; done
Você conseguiu encaixar algumas práticas ruins de script de shell:
Embora eu deva ter mencionado pela primeira vez Por que usar um loop de shell para processar texto é considerado uma prática ruim? .
Tente, por exemplo, em uma entrada como:
-n
/*/*/*/../../../*/*/*
foo\
bar
Se você realmente precisou usar um loop de shell, provavelmente teria que ser algo como:
{
while IFS= read <&3 -r i; do
printf '%s\n' "$i" || exit
done
[ -z "$i" ] || printf %s "$i" || exit
} 3< test.txt
Em
for i in $(cat test.txt); do echo $i; done
Isso substitui uma prática ruim por outra. Aqui, você tem uma boa razão para deixar $(cat test.txt)
sem aspas: você quer a parte dividida do operador split + glob, mas esqueceu de especificar o que deseja dividir e desativar a parte glob.
IFS='
' # split on newline only. The default value of $IFS
# contains space, tab and newline which explains why you see
# one word per line
set -o noglob # disable glob
for i in $(cat test.txt); do
printf '%s\n' "$i" || exit
done
Observe que ainda seria possível pular as linhas vazias, e que lê e armazena o conteúdo do arquivo na memória (várias vezes) antes de iniciar o loop.