Como faço para grep o texto depois de dois caracteres especiais?

4

Eu quero usar os dados após > & amp; %código%. Eu usei este comando:

grep -o '  |.*$'| cut -c5-

Mas é só dar os dados depois de | :

                                                              > Aminobenzoate
Asthma                                                        | Atrazine
Autoimmune thyroid disease                                    | Bacterial
B cell receptor signaling pathway                             | Benzoate
Bile secretion                                                | beta-Lactam
                                                              > Biosynthesis
Caffeine metabolism                                           | Caprolactam
Calcium signaling pathway                                     | Carbapenem

Saída desejada:

Aminobenzoate
Atrazine
Bacterial
Benzoate
beta-Lactam
Biosynthesis
Caprolactam
Carbapenem
    
por Rhea 12.05.2017 / 07:46

6 respostas

5

Sugiro usar sed para isso:

sed 's/.*[|>] *//'

Isso funciona para o seu exemplo, mas talvez seja necessário adaptá-lo, dependendo do que fazer com as linhas sem | ou > . Se esses devem ser removidos completamente, use

sed -n 's/.*[|>] *//p'

Isso significa que a saída não é por padrão (opção -n ), mas imprima uma linha ( p ), se o comando s puder realizar uma substituição.

    
por Philippos 12.05.2017 / 07:55
4

awk também pode ser usado. Você pode usar vários separadores de campo usando -F com awk para obter os > e | . Também pode usar a opção sub para limpar o primeiro espaço inicial que aparece antes do texto quando ele imprime as colunas correspondentes:

 awk -F'[>|]' '{sub(/^\ /, "",); print }' file.txt
    
por Terrance 12.05.2017 / 08:36
3

Usando o awk:

awk -F'[>|]' '{print}' input.txt | awk -F' ' '{print}'

OR

Sugerido por Sergiy Kolodyazhnyy

awk -F'[>|]' '{print substr(,2)}' input.txt
    
por d a i s y 12.05.2017 / 08:01
3

Primeiro de tudo, acredito que esta é uma saída diff -y , então você também pode incluir < .

Nós só podemos usar o grep para fazer isso através do olhar para trás:

grep -Po "(?<=(\||<|>)\s).*" file.txt
  • .* Procure por qualquer coisa repetida vezes.
  • (?<=(\||<|>)\s) , que está por trás de um desses ( | ou < ou > ) seguido por um espaço.

uma versão mais clara é:

grep -Po '(?<=[<|>]\s).*' file.txt

Ou usando grep e cut como você estava tentando:

grep -Eo "(<|>|\|).*" file.txt | cut -f2 -d' '
  • -E : estendido grep
  • -o Imprimir apenas a parte correspondente
  • (<|>|\|) significa < ou | ou > .
  • .* every thing & amp; qualquer momento repetido

O que nos leva a esse ponto:

enter code here
> Aminobenzoate 
| Atrazine 
| Bacterial 
| Benzoate 
| beta-Lactam 
> Biosynthesis 
| Caprolactam 
| Carbapenem

então, usando cut , obtemos o segundo campo que são nossas sequências, que é:

Aminobenzoate
Atrazine
Bacterial
Benzoate
beta-Lactam
Biosynthesis
Caprolactam
Carbapenem
    
por Ravexina 12.05.2017 / 11:39
3

Perl

Aqui está um perl one-liner que faz o trabalho:

$ perl -ne 's/^.*[|>]\ //;print' inp.txt                                                
Aminobenzoate 
Atrazine 
Bacterial 
Benzoate 
beta-Lactam 
Biosynthesis 
Caprolactam 
Carbapenem

Ou ainda mais curto, como sugerido por Matija Nalis nos comentários

perl -pe 's/^.*[|>]\ //' inp.txt 

Basicamente, ele pega e exclui tudo, desde o início da string até | ou > e, em seguida, imprime o material.

Sed alternativo com agrupamento

Se você ainda não percebeu, todas as respostas aqui funcionam com a idéia de excluir as informações principais. O que também podemos fazer é grupo o que queremos e substituir toda a linha por isso. O foco não é na informação principal, mas nas coisas que realmente queremos na saída.

Tome por exemplo este sed

$ sed 's/^.*[>|] \(.*$\)//' inp.txt                                                     
Aminobenzoate 
Atrazine 
Bacterial 
Benzoate 
beta-Lactam 
Biosynthesis 
Caprolactam 
Carbapenem

O que acontece é que o que estiver dentro de \( e \) será tratado como um todo e referenciado por . Esse comando basicamente diz "pegue o que vier depois de > ou | mais um espaço e faça como um grupo, e substitua toda a linha pelo que colocamos nesse grupo .

Python

Embora os scripts python possam ser um pouco mais longos, eles geralmente são mais legíveis e explícitos. Veja o que poderíamos fazer com o script do Python 3:

#!/usr/bin/env python3
import sys
import re
with open(sys.argv[1]) as fd:
    for line in fd:
        print(re.split("<|>|\|",line.strip())[1].strip())

As principais ideias aqui são as seguintes:

  • nós abrimos qualquer arquivo que seja fornecido como argumento de linha de comando
  • iteramos sobre cada linha do arquivo
  • usando a função re.split() , dividimos cada linha em lista usando > ou | ou > como separador.
  • Em seguida, extraímos o segundo item (índice [1] na lista, porque as listas começam no índice de 0) nessa lista e, usando strip() function, removemos os espaços em branco inicial e final.
  • Todas essas ações de re.split() e extração de lista ocorrem dentro da função print() , portanto, quando todas essas operações estiverem concluídas, obtemos a sequência de saída desejada e prosseguimos para processar a próxima linha

Se quiséssemos, poderíamos sempre enfiar tudo em uma única linha assim:

$ python -c 'import re,sys;print("\n".join([ re.split("<|>|\|",l.strip())[1].strip() for l in sys.stdin]))' < inp.txt    
Aminobenzoate
Atrazine
Bacterial
Benzoate
beta-Lactam
Biosynthesis
Caprolactam
Carbapenem

Outras notas secundárias:

  • se esta for realmente uma saída diff , como a resposta de Ravexina sugere , podemos sempre incluir < em todas as expressões aqui apresentado adicionando < em colchetes. Assim teremos:
    • perl -pe 's/^.*[|><]\ //;' inp.txt
    • sed 's/^.*[><|] \(.*$\)//' inp.txt
    • A solução Python foi escrita depois que isso se tornou uma consideração, de modo que a solução já inclui <
por Sergiy Kolodyazhnyy 12.05.2017 / 08:33
0

A menor quantidade de modificação do seu comando atual seria substituir sua menção ao caractere literal | em seu regex por uma referência a uma classe de caracteres contendo ambos | e > , [|>] , que irá corresponder a qualquer um deles:

grep -o '  [|>].*$'| cut -c5-

Outros exploraram as implementações awk , sed e perl , mas a implementação grep também pode ser melhorada.

Por exemplo, você pode se livrar do comando cut das seguintes maneiras:

  • usando o \K flag do Perl: grep -Po '[>|]\s*\K.*
  • usando o lookbehind do PCRE: grep -Po '(?<=[|>]\s).*' note que isso só funcionará com uma quantidade fixa de espaços entre o delimitador e a palavra de destino, pois os mecanismos PCRE não precisam implementar lookbehind de largura variável e geralmente não o fazem.
por Aaron 12.05.2017 / 15:58