O problema não é com $file
, é com o uso de $(find…)
.
As variáveis regulares e as substituições de $(…)
do processo estão sujeitas exatamente ao mesmo tipo de divisão de palavras. Se você colocar $(find…)
entre aspas, você obtém uma palavra única com todas as saídas. Se você não o fizer, ele será dividido em qualquer espaço em branco - não apenas as linhas novas ou algum outro limite mágico que você provavelmente esperava.
Uma parte importante do que foi dito acima é que escapes de barra invertida não são processados quando a variável é expandida. É apenas dividido em espaços e é isso.
(Em outras palavras, citar $file
não ajudou porque nunca teve o valor correto em primeiro lugar!)
Se você quiser processar todos os arquivos recursivamente, suas opções são:
-
Ler a saída de
find
de outra maneira:find … -print | while read -r file; do echo "Got $file" done
(Nota lateral: os nomes dos arquivos podem incluir tecnicamente também novas linhas, por isso você pode querer evitar isso, por mais raro que seja:
find … -print0 | while read -r -d "" file; do echo "Got $file" done
-
Para pequenas quantidades de arquivos, use os curingas estendidos do bash:
shopt -s globstar for file in /path/to/foo/**; do echo "Got $file" done
Com diretórios grandes, a vantagem de find | while read
é que ele é transmitido - seu script processará os resultados conforme eles são exibidos. Enquanto isso, $(find)
e curingas têm que coletar tudo na memória primeiro, e só então retornar os resultados (possivelmente massivos).
Por outro lado, o uso de um pipe afeta o loop inteiro while
(não apenas o comando read
), portanto, se você quiser executar qualquer coisa que quer ler a entrada do teclado, você tem que fornecer manualmente o stdin original, por exemplo vim "$file" < /dev/tty
.