Como classificar essas linhas neste arquivo ASCII

0

O arquivo ASCII que tenho é o seguinte:

a
1 2 3
1223
b
1 2 3 5
3344
1223
c
1 2 34
a
4 5
c
123

Como faço para coletar as linhas abaixo de a, b, c, respectivamente?

P: O que eu faria para obter as linhas abaixo?

a
1 2 3
1223
4 5
    
por questionhang 10.03.2015 / 20:59

4 respostas

1

Aqui está uma solução awk que faz de tudo para impedir a impressão da segunda a :

awk '$1 == "a" { if (!head) print; n=head=1; next } $1 !~ /^[0-9]/ { n=0 } n' ascii_file

Substitua "a" por "b" para obter esses resultados, etc.

Saída:

a
1 2 3
1223
4 5

Se você quisesse um loop, poderia fazer assim:

for letter in a b c; do
  echo
  awk -v letter="$letter" '$1 == letter { if (!head) print; n=head=1; next } $1 !~ /^[0-9]/ { n=0 } n' /tmp/a
done

que teria essa saída:

a
1 2 3
1223
4 5

b
1 2 3 5
3344
1223

c
1 2 34
123

(Observe a linha echo . Isso delimita entre os hits de cada consulta. Estruturei essa resposta para permitir que você consultasse por carta, que é o meu entendimento da pergunta.)

    
por 10.03.2015 / 21:25
2
awk '/^[a-z]$/ { f = $1=="a" ; if (!c++) print ; next }; f'
    
por 10.03.2015 / 21:31
2

Ah, awk torna as coisas muito mais fáceis, usando apenas uma passagem pelos dados, ao contrário das outras soluções que vi até agora:

/^[a-z]/{key=$0;} 
/^[0-9]/{if (key in res){ res[key]=res[key] "\n" $0;} else {res[key]=$0;}} 
END {for(key in res){
    print key; 
    print res[key];
    }}

Se você deseja que sed + apenas funcione, isso parece funcionar:

 cat data.txt | sed -e '/^a/,/^[b-z]/!d' | sed -e '2,${ /^[a-z]/d }'

(Sim, é um uso inútil de gato por razões didáticas, ou seja, fico confuso quando o arquivo está em algum lugar no meio dos meus cachimbos.)

O primeiro sed considera todos os intervalos que começam com uma linha iniciando a e terminam com uma linha começando com uma letra b-z , inclusive. Ele nega esse intervalo (o ! ) e, em seguida, exclui tudo que foi correspondido, então ficamos com

a
1 2 3
1223
b
a
4 5
c

O segundo sed examina apenas o intervalo da linha 2 até o final do arquivo (para manter o a header) e, dentro disso, exclui todas as linhas que começam com uma letra a-z , restando apenas as linhas numéricas:

a
1 2 3
1223
4 5

Para obter uma lista de todos os seus cabeçalhos, eu tentaria grep '^[a-z]' | sort -u . então toda a besta é:

for key in $(grep  '^[a-z]' data.txt | sort -u ); do 
    cat data.txt | sed -e "/^$key/,/^[b-z]/\!d" | sed -e '2,${ /^[a-z]/d }'  ; 
done
    
por 10.03.2015 / 21:21
2
awk '
/^[a-z]$/{
  i=$0
  next
  }
{
  A[i]=A[i] "\n" $0
  }
END{
  for (j in A)
    print j A[j]
  }'

Como você pode ver, é uma variante simplificada do script @Ulrich Schwarz : para linhas que consistem em apenas 1 carta pegue esta letra como índice i e inicie o novo loop de linha. Em seguida, coloque todas as linhas remanescentes (que não "consistem apenas em 1 letra inferior" porque já operou antes) na matriz de associação A de acordo com i ndex estabelecida na parte anterior do script com \n ewline separator. Quando o script transmitir todas as linhas (alcance END ), imprima a matriz A por i ndexes.

    
por 10.03.2015 / 23:22