git-bash como lidar com espaços em nomes de arquivos

1

Eu escrevi o seguinte script para rodar sob o 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 tem um espaço nele. Eu pensei que as aspas duplas deveriam cuidar disso, mas não é cooperativo.

Idéias?

Como alternativa, você pode dizer o que estou tentando fazer. Qualquer outra sugestão seria bem-vinda.

    
por Thom 16.04.2018 / 15:33

1 resposta

3

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).

    
por 16.04.2018 / 15:46