A saída de uma substituição de comando está sujeita à divisão de palavras (a qual você cuidou definindo IFS ), e globalização de nome de arquivo. A construção [abc] é "corresponde a qualquer um dos caracteres a , b , c " como de costume e
[2006_02_25].doc corresponde a 0.doc .
No Bash / ksh / zsh, você pode usar a estrela dupla para obter todos os arquivos na árvore de diretórios (recursivamente, não apenas no diretório atual). Isso deve encontrar os mesmos arquivos do seu exemplo:
shopt -s globstar # in Bash
# set -o globstar # in ksh
for file in **/* ; do
[[ -f $file ]] || continue # check it's a regular file, like find -type f
...
done
Naturalmente, find é poderoso, então usá-lo pode ser mais fácil se você tiver muitas condições. Se fizer isso, você deve desabilitar o globbing de nomes de arquivo com set -f além de corrigir IFS :
set -f
IFS=$'\n'
for file in $(find -type f -some -other -conditions) ; do
...
done
ou use um loop while read com substituição de processo:
while IFS= read -r file ; do
...
done < <(find -type f -some -other -conditions)
(O acima é semelhante a find ... | while ... , mas ignora o problema da última parte de um pipeline sendo executado em um subshell.)
Ambos supõem que os nomes de arquivos não contêm novas linhas, pois são usados como separador para a saída de find . (e porque $(..) come novas linhas finais.)
No Bash, pelo menos, há uma maneira de fazer com que novas linhas de nomes funcionem também. Configurar o read delimitador para a cadeia vazia faz com que ele use efetivamente o byte NUL como delimitador. Então:
while IFS= read -d '' -r file ; do
...
done < <(find -type f -some -other -conditions -print0)
Embora isso esteja começando a ficar difícil de escrever, já que você precisa de todas essas opções para read para fazê-lo funcionar sem atrapalhar a entrada.
Quanto ao IFS ... Configurar IFS=$(echo -en "\n"); conjuntos IFS para a cadeia vazia (porque a substituição de comando come a nova linha à direita), resultando na divisão não . A saída, neste caso, parece correta, já que você obtém toda a saída de find de uma só vez, não linha por linha. Isso também mascara o problema com o globbing de nomes de arquivos, já que a string multilinha completa não corresponde a nenhum nome de arquivo e é passada como está.
Você pode ver a diferença se fizer qualquer outra coisa além de imprimir o valor do loop. Tente adicionar alguns separadores:
IFS=$(echo -en "\n") # same as IFS=
for FILE in $(find -type f); do echo "<$FILE>"; done
De longe, a maneira mais fácil de definir IFS para uma nova linha em qualquer coisa, exceto nas conchas padrão mais básicas, é IFS=$'\n' .