Obter números que correspondam a um padrão da saída de ls?

5

Eu tenho uma pasta e, quando executo ls , ela gera

t-1-myFirstTest.c
myFile.c
t-42-my_second_test.c
t-3-test1234.c
  .
  .
  .
mySecondFile.c
t-21-tset241.c

Desejo excluir tudo deste texto, exceto as novas linhas e os números entre t- e o segundo - . Então a saída deste anterior deve ser

1
42
3
 .
 .
 .
21

Eu tenho uma solução, mas acho que é muito ruim. Se a pasta sobre a qual estamos falando estiver realmente no diretório atual, usei

ls | grep -o -E t-[0-9]+-[a-zA-Z0-9_]+.c | grep -o -E t-[0-9]+ | grep -o -E [0-9]+

Qualquer maneira melhor de realizar a mesma coisa?

    
por Garmekain 17.07.2018 / 12:14

4 respostas

3

Analisar a saída de ls é uma má ideia (a saída de ls é estritamente para olhar). Para mais informações, consulte a pergunta " Por que * not * pars 'ls'? ".

É assim que você pode fazer isso em /bin/sh :

for filename in t-*-*.c; do
    [ ! -f "$filename" ] && continue
    number=${filename#t-}   # remove "t-" from start of filename
    number=${number%%-*}    # remove everything from first "-" in what remains
    printf '%s\n' "$number"
done

Isso iterará todos os nomes de arquivos no diretório atual cujo nome corresponda ao padrão t-*-*.c . Para cada um desses nomes, o t- bit é retirado do início e, em seguida, o segundo - e tudo depois é removido com outra expansão de parâmetro.

A expansão ${variable#word} removeria a correspondência (mais curta) de word do início de $variable , enquanto ${variable%%word} removeria a correspondência (mais longa) de word do o fim da string.

Com bash , usando a expressão regular correspondente nos nomes dos arquivos:

for filename in t-*-*.c; do
    [ ! -f "$filename" ] && continue
    if [[ "$filename" =~ ^t-([0-9]+)- ]]; then
        printf '%s\n' "${BASH_REMATCH[1]}"
    fi
done

Isso corresponderia e capturaria os dígitos após t- em cada nome de arquivo. O grupo de dígitos capturado está disponível em ${BASH_REMATCH[1]} após uma correspondência bem-sucedida. O índice 1 refere-se ao primeiro grupo de captura (parênteses) na expressão regular.

Para uma solução lenta, mas possivelmente confortável (como em "familiar"), convém chamar um comando externo para analisar o bit da string em que você está interessado:

for filename in t-*-*.c; do
    [ ! -f "$filename" ] && continue
    cut -d '-' -f 2 <<<"$filename"
done

Isso pressupõe bash e você pode chamar cut em um loop. Isso seria muito mais lento do que usar a operação embutida no próprio shell. O comando cut aqui é solicitado a retornar o segundo campo - -delimited da string passada para ele a partir de bash (usando um redirecionamento "here-string").

    
por 17.07.2018 / 12:46
3

De acordo com sua saída:

ls|awk -F"-" '{print $2}'

Deve funcionar, mas se você quiser levar em conta a t- parte, então

ls|grep ^t-|awk -F"-" '{print $2}'

ou

ls|awk -F"t-" '{print $2}'|awk -F"-" '{print $1}'

    
por 17.07.2018 / 12:48
3

Quando criei a lista de arquivos do seu exemplo, meu ls os classifica dessa maneira:

$ ls -1
myFile.c
mySecondFile.c
t-1-myFirstTest.c
t-21-tset241.c
t-3-test1234.c
t-42-my_second_test.c

Como resultado, a função bash abaixo exibe as novas linhas e os números dos arquivos na mesma ordem.

I want to delete everything of this text except the newlines and the numbers between t- and the second -

Eu interpretei isso para dizer que os nomes de arquivos que não correspondem a t- devem ser "excluídos, exceto para a nova linha", significando: imprima uma linha em branco para esses nomes, mas forneça os números entre os traços.

lsnums ()
{
    for f in *
    do
        if [[ "$f" =~ t-([[:digit:]]+)- ]]; then
            printf '%s\n' "${BASH_REMATCH[1]}"
        else
            echo
        fi
    done
}

A saída resultante é:

$ lsnums


1
21
3
42

... onde as duas linhas em branco correspondem aos arquivos do primeiro tipo começando com my em vez de t- .

    
por 17.07.2018 / 14:26
1

Pode ser feito simplesmente com:

ls | cut -d '-' -f 2
    
por 17.07.2018 / 15:50