Como obter a substring de um nome de arquivo que corresponda a um caractere curinga “*” glob?

3

Digamos que eu tenha um diretório com os seguintes arquivos (entre outros):

touch doc-mike.txt doc-jane.txt doc-susan.txt

Eu posso fazer algo em um script com esses arquivos usando um constructo como:

for fname in doc-*.txt; do
    echo input: ${fname}
done

Mas se eu quiser obter a subseqüência do nome do arquivo que corresponde ao caractere curinga, tenho que passar por alguns arcos feios:

for fname in doc-*.txt; do
    wildcard=${fname#doc-}
    wildcard=${wildcard%.txt}

    echo input: ${fname} output: output-${wildcard}.results
done

Isso funciona:

input: doc-jane.txt output: output-jane.results
input: doc-mike.txt output: output-mike.results
input: doc-susan.txt output: output-susan.results

mas acho que tem de haver uma maneira melhor / mais fácil de obter a substring que corresponda ao curinga "*" glob

    
por Michael Burr 07.04.2018 / 08:09

3 respostas

4

O mais próximo que eu posso pensar é BASH_REMATCH , já que o bash armazena os resultados de um texto regex na variável:

$ for fname in doc-*.txt; do 
    [[ $fname =~ doc-(.*).txt ]];
    echo "input: ${fname} output: output-${BASH_REMATCH[1]}.results";
done
input: doc-jane.txt output: output-jane.results
input: doc-mike.txt output: output-mike.results
input: doc-susan.txt output: output-susan.results

Como (.*) é o primeiro grupo na regex, está em BASH_REMATCH[1] . Eu acho que esse é o comportamento que você quer, mas com globs, eu não acho que o bash o disponibilize de qualquer forma.

    
por 07.04.2018 / 08:37
1

Você também pode tentar

for fname in doc-*.txt; do 
  echo "input: ${fname} output: output-${fname:4:$((${#fname}-8))}.results"
done
    
por 07.04.2018 / 15:14
1

Com zsh , você pode usar uma combinação de qualificadores glob, modificadores de expansão de histórico e sinalizadores de globbing fazer isso.
Supondo que você tenha habilitado a globalização estendida e o modo de substituição do padrão de histórico via

setopt extendedglob
setopt histsubstpattern

você pode então executar

print doc-*.txt(#q:s/(#b)doc-(*).txt/'${match[1]}'/)

qual produzirá

jane mike susan

Como de costume, você pode combinar isso com outros qualificadores / modificadores / sinalizadores, por exemplo selecione apenas arquivos regulares, ancore a expressão ao início / fim da palavra, etc.

Embora se você quisesse iterar sobre cada nome de arquivo, com zsh você pode aninhar expansões de parâmetro para que seu código pudesse ser simplificado para

for fname in doc-*.txt; do
    print input: ${fname} output: output-${${fname#doc-}%.txt}.results
done

Os itens acima (re: seu comentário ) usa uma única expressão e não precisa de uma variável intermediária.

    
por 07.04.2018 / 16:23