Solução 1
A solução mais próxima é usar find
com -print0
e ler a saída com while read …
:
find -name "*.log" -o -name "*.err" -o -name "*.out" -type f -print0 | while IFS= read -r -d '' logfile; do
...
Continue usando "$logfile"
com aspas, como sempre deveria ao usar variáveis.
Solução 2
Outra solução seria não usar find
e deixar apenas grep
ser executado em vários arquivos:
shopt -s nullglob
shopt -s globstar
grep "api/" **/*.log **/*.err **/*.out
Aqui, globstar
ativa a correspondência recursiva de diretórios com **
. Você deve definir nullglob
para evitar erros se uma dessas extensões de arquivo não existir.
Isso só funciona para um conjunto limitado de arquivos, pois você pode atingir o tamanho máximo dos argumentos da linha de comando.
Por que o erro acontece?
Você nunca deve executar for
na saída de find
(ou ls
ou qualquer outra função que produza nomes de arquivos com espaço em branco). Leia este artigo para mais informações sobre por que isso é um problema e o que pode ser feito para resolvê-lo.
Em suma, o Bash divide os argumentos por espaço em branco. Imagine que você tenha três arquivos, a
, foo bar
e b
, e a linha será calculada para:
for logfile in a foo bar b; do
Obviamente, o Bash definirá logfile
para a
, foo
, bar
e b
, que não é o que você queria. Se você pudesse especificar manualmente a entrada para for
, você colocaria esses nomes de arquivo entre aspas para resolver o problema.
Para fazer isso automaticamente, a solução é delimitar esses nomes de arquivos com um caractere NUL
(que é o que a opção -print0
faz) e dividir a saída com base nesse caractere NUL
novamente (que é o -d ''
em read
faz).