Como imprimir as linhas anteriores da palavra-chave de pesquisa sem usar grep em um arquivo gz?

2

Como imprimir as linhas antes de uma palavra-chave de pesquisa sem usar grep em um arquivo .gz?

ID:342N000390AAAAAAAA   07/14/15 10:26      (MV90    )
         * Register Data Imported
         * Warning - No Profile Data
     07/14/15 10:24  05/13/15 08:16       15    1   5956

Eu quero pesquisar a palavra-chave No Profile e imprimir o NÚMERO de ID que é 342N000390AAAAAAAA e necessariamente "Nenhum perfil" não virá na terceira linha; pode vir em qualquer linha. Meu sistema operacional é o HP-UX, portanto, muitos comandos não são elegíveis.

    
por Pooja 24.07.2015 / 09:36

3 respostas

3

Você poderia trabalhar com awk :

gzcat file.gz | awk '/No Profile Data/{printf "%s\n%s\n%s\n", b, a, $0} {b=a;a=$0}'
  • gzcat (ou zcat no Linux) imprime o conteúdo do arquivo gzipado na saída padrão
  • awk , em seguida, procura a string "No Profile Data" e imprime as duas linhas anteriores
por 24.07.2015 / 09:54
2

Editado

Nova abordagem: remoção de quebras de linha.

Supondo que você tenha apenas um ID por arquivo gzipado, tente o seguinte:

gunzip -c file.gz | sed -e ':a;N;$!ba;s/\n/ /g' -e '/^[[:space:]]/d' -e 's/^ID:\([[:alnum:]]*\).*Warning - No Profile Data.*//' -e '/^ID:/d'
  • gunzip -c extrai o arquivo para stdout
  • sed recolhe todas as linhas em uma, remove todas as linhas que não estão iniciando com ID: , extrai a ID dos arquivos correspondentes e remove a ID: line para arquivos não correspondentes, para exibir a ID ou nada.

Créditos devidos ao link e link @DarkHeart

Original

grep ainda é a opção adequada, mas, para o exercício, você pode usar sed para a descoberta e paste para a -B2 part:

zcat nogrep.gz | paste - - - | sed -e '/^[[:space:]]/d' -e 's/^ID:\([[:alnum:]]*\).*Warning - No Profile Data//' -e '/^ID:/d'
  • paste une cada grupo de 3 linhas
  • sed remove todas as linhas que não estão iniciando com ID: , depois extrai o ID dos arquivos correspondentes e, em seguida, remove a linha ID: dos arquivos não correspondentes, para exibir o ID ou nada.
por 24.07.2015 / 10:00
2

(esperançosamente) o produto final

find . -name \*.gz -type f -exec   gzcat {} +  |
sed -ne'/^ *ID:/h;/No Profile/!d;x' \
    -e's/^ *ID:\([^ ]*\).*//p'

Para que recursivamente find todos os arquivos regulares com raiz no diretório atual com nomes de arquivos que correspondam ao padrão *.gz e chame zcat quantas vezes forem necessárias para descomprimir iterativamente cada um em um único fluxo para sed 's stdin.

sed varrerá sua entrada para as linhas com a string *ID: . Será h old uma cópia se encontrada e, em seguida, procurar No Profile enquanto d elimina todas as linhas que não correspondem. Quando encontrado, sed irá trocar para o espaço de espera e tentar cortar uma linha ^ *ID: para apenas a parte que cai entre o primeiro : e o próximo ocorrendo espaço> . Se tiver sucesso, sed p solicitará os resultados.

Como @ DarkHeart aponta você provavelmente terá que alterar o nome do comando zcat para gzcat em um sistema HPUX, embora.

variações

Isso seria tudo o que você precisa para procurar em um único arquivo por pares de linhas ocorrendo imediatamente antes de uma correspondência para a string No Profile :

gzip -d <file.gz |
sed -e'1N;$!N;/\n.*No Profile/P;D'

Isso apenas digitalizará três linhas de cada vez. Cada linha é separada por um \n ewline no espaço padrão. Como cada linha N ew é enviada, a mais antiga é D eleted. Se o regexp \n.*No Profile for sempre combinado no espaço de padrões (como será quando for a linha mais nova no espaço de padrões e o ciclo seguinte quando for o segundo a mais recente) , a linha mais antiga é impresso. E assim você obtém as duas linhas que ocorrem antes de No Profile . Se você quiser também imprimir a linha na qual ele é encontrado ...

gzip -d <file.gz |
sed -e'1N;$!N;/No Profile/P;D'

com find :

find . -name \*.gz -type f -exec zcat {} + |
sed -e'1N;$!N;/No Profile/P;D'

Você pode trocar o . pelo nome de algum diretório, se quiser. Você também pode adicionar o bit \n.*No Profile para evitar imprimir a linha correspondente. Esse comando recorrerá a todos os diretórios filhos de . . Se isso não é do seu agrado:

find . \! -name . -prune -name \*.gz  \
          -type f -exec zcat {} +     |
sed -e'1N;$!N;/No Profile/P;D'

Se você estiver procurando especificamente pelo campo ID líder e somente se puder encontrar duas linhas antes de uma correspondência para No Profile , você poderá fazer:

find . -name \*.gz -type f -exec zcat {} + |
sed -ne'/^ID/!D;/\n/!N;N' \
     -e's/ .*\n.*\n.*No Profile.*//p;D'

..., que imprime apenas o campo ID líder, como pode ocorrer em qualquer / todos os arquivos *.gz find calls zcat para imprimir e somente se ID definitivamente ocorrer em duas linhas antes de uma correspondência No Profile .

    
por 27.07.2015 / 11:54