![Como lidar com espaços em nomes de arquivos no Git Bash](https://rvso.com/image/1558675/Como%20lidar%20com%20espa%C3%A7os%20em%20nomes%20de%20arquivos%20no%20Git%20Bash.png)
Eu escrevi o seguinte script para ser executado no Git Bash no Windows 7:
#!/usr/bin/env sh
for logfile in `find -name "*.log" -o -name "*.err" -o -name "*.out"`
do
echo $logfile
grep "api/" "$logfile"
done
O problema é que o grep engasga quando um nome de arquivo contém um espaço. Achei que as aspas duplas deveriam resolver isso, mas não é uma cooperação.
Ideias?
Responder1
Solução 1
A solução mais próxima é usar find
with -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"
aspas, como sempre deve fazer ao usar variáveis.
Solução 2
Outra solução seria não usar find
nada e apenas deixar grep
rodar em vários arquivos:
shopt -s nullglob
shopt -s globstar
grep "api/" **/*.log **/*.err **/*.out
Aqui, globstar
permite 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.
Porém, isso funciona apenas para um conjunto limitado de arquivos, pois você pode atingir o comprimento 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ços em branco). LerEste artigopara obter mais informações sobre por que isso é um problema e o que pode ser feito para resolvê-lo.
Resumindo, o Bash divide os argumentos por espaços em branco. Imagine que você tem três arquivos, a
e foo bar
, b
então a linha seria avaliada como:
for logfile in a foo bar b; do
Obviamente, o Bash será definido logfile
como a
, foo
, bar
e b
, o que não é o que você queria. Se você pudesse especificar manualmente a entrada para for
, colocaria esses nomes de arquivos entre aspas para resolver o problema.
Para fazer isso automaticamente, a solução é delimitar esses nomes de arquivos com um NUL
caractere (que é o que a -print0
opção faz) e então dividir a saída com base nesse NUL
caractere novamente (que é o que o -d ''
in read
faz).