Como contar facilmente o número de correspondências de um glob envolvendo caminhos com espaços?

0

Estou lidando com caminhos que terão espaços.

Eu estou circulando dessa maneira (a segunda linha configura o glob):

IFS=$'\n'

VAR="$1/"name_*

for file in $VAR; do
  echo $file
  grep ITEM "$file" | wc -l
done

Eu preciso procurar apenas em arquivos com o nome name_* em $1 . O IFS configurado aqui me permite ver os arquivos corretamente, porque impede que for fique sobrecarregado por espaços em nomes de arquivos.

No entanto, agora quero uma maneira fácil de obter o número total de arquivos desse tipo correspondidos pelo glob. Eu sei que posso usar um contador no loop for, mas eu estava esperando que eu pudesse usar um pipe com meu VAR para fazer isso.

No entanto, se eu echo $VAR , a globalização ocorre com sucesso, mas os diferentes caminhos são unidos pelo espaço, o que me arruína porque agora não consigo mais separar os itens ... Existe uma maneira de substituir esse comportamento semelhante a como o IFS funciona em for ?

    
por Steven Lu 02.10.2018 / 04:34

2 respostas

1

Você deve evitar usar / expandir strings se o que você deseja é uma lista de valores separados.

A solução básica é definir os parâmetros posicionais:

set -- "$1"/name_*

Isso manterá cada arquivo correspondente em um parâmetro posicional separado, mesmo com espaços ou novas linhas (ou a maioria dos outros caracteres).

No bash, você deve definir shopt -s failglob para fazer o script parar se nenhum arquivo for correspondido pelo glob ( * ), ou shopt -s nullglob se você quiser obter nenhum resultado (ao contrário do próprio glob "$1"/name_* ) se o glob não corresponder a nenhum arquivo. Mantenha o failglob desativado para evitar parar o script.

A contagem de arquivos ( conta o número de correspondências de uma glob ) é agora simplesmente:

echo "$#"

a contagem de parâmetros posicionais.

O loop for reduziria para:

for file
do  echo "$file"
done

Isso evita completamente problemas com a divisão em IFS .

Observe que os valores externos $1 devem ser citados para evitar a injeção de código.
Como também o echo "$file" deve ser citado.

Também é possível atribuir uma lista a um array:

files=( "$1"/name_* )

Isso evitará a invasão dos parâmetros posicionais, mas tornará a sintaxe um pouco mais complexa. A contagem de elementos na matriz é:

echo "${#files[@]}"

E o loop precisará de algumas alterações:

for file in "${files[@]}"; do
    echo "$file"
done
    
por 02.10.2018 / 05:38
0

Você poderia resolver o problema de espaços e obter a contagem se você mudasse para arrays:

VAR=("$1/"name_*) # make array of filenames matching glob

echo "${#VAR[@]}" # number of elements in array

for file in "${VAR[@]}"; do  # loop over individual elements of array
  echo "$file"
  grep ITEM "$file" -c  # grep can count, wc isn't needed
done
    
por 02.10.2018 / 04:45

Tags