Depende do que file
deve conter. Se for destinado a conter uma lista separada por IFS de globs de shell como (assumindo o valor padrão de $IFS
):
/var/log/*.log /var/adm/*~
/some/dir/*.txt
Então for i in $(cat file)
seria o caminho a percorrer. Como é isso que $(cat file)
sem aspas: aplica o operador split + glob na saída de cat file
de seus caracteres de nova linha à direita. Por isso, passaria por cima de cada nome de ficheiro resultante das expansões desses globs (excepto nos casos em que os globs não correspondem a nenhum ficheiro em que isso deixaria o glob lá, mas não expandido).
Se você quisesse fazer um loop por cada linha delimitada de file
, você faria:
while IFS= read -r line <&3; do
{
something with "$line"
} 3<&-
done 3< file
Com um loop for
, você pode percorrer todas as linhas não vazias com:
IFS=' ' # split on newline only (actually sequences of newlines and # ignoring leading and trailing ones as newline is a # IFS whitespace character) set -o noglob # disable the glob part of the split+glob operator: for line in $(cat file); do something with "$line" done
No entanto, um:
while read line; do
something with "$line"
done < file
Faz pouco sentido. Isso é lendo o conteúdo de file
de uma maneira muito complicada , onde caracteres de $IFS
e barras invertidas são tratados especialmente.
Em qualquer caso, o limite ARG_MAX ao qual você está citando refere-se à chamada de sistema execve()
(no tamanho cumulativo dos argumentos e variáveis de ambiente), portanto, aplica-se somente aos casos em que um comando no sistema de arquivos está sendo executado com a expansão possivelmente muito longa do operador split + glob aplicado à substituição de comando (esse texto é enganoso e errado em várias contas).
Seria aplicável por exemplo em:
cat -- $(cat file) # with shell implementations where cat is not builtin
Mas não em:
for i in $(cat file)
em que não há nenhuma chamada de sistema execve()
envolvida.
Compare:
bash-4.4$ echo '/*/*/*/*' > file
bash-4.4$ true $(cat file)
bash-4.4$ n=0; for f in $(cat file); do ((n++)); done; echo "$n"
523696
bash-4.4$ /bin/true $(cat file)
bash: /bin/true: Argument list too long
Tudo bem com o comando bash
builtin de true
ou com o loop for
, mas não ao executar /bin/true
. Observe como o file
tem apenas 9 bytes, mas a expansão de $(cat file)
é de vários megabytes porque o /*/*/*/*
glob está sendo expandido pelo shell.
Mais leitura em: