Obtém o primeiro padrão correspondente em uma linha que não usa corte

3

ter um monte de textos semelhantes a isso (com o objetivo de testar e manter os dados mais simples possível):

first 1 is the real 2 time the word matched 3 
appeared on the previous line but is 4 the fourth.
Every line can have more numbers 5 because numbers 6 are everywhere
I need to extract the number just after the word 7 that precedes 8

O comando grep que estou testando para extrair a primeira correspondência para o número logo após a palavra ser:

grep -Eoi ' [0-9]{1}'

a saída é:

 1
 2
 3
 4
 5
 6
 7
 8

A saída desejada é:

 1
 4
 5
 7

Não é permitido usar cut nem awk .

    
por jomaweb 14.12.2016 / 09:39

5 respostas

3

Eu suspeito que este seja um tipo de exercício somente para o grep. A solução grep pura é esta:

Em uma única linha:

echo "first 1 is the real 2 time the word matched 3 " |grep -Eo '[0-9]' |grep -m1 -E '[0-9]'

Infelizmente, usar grep -m1 no primeiro grep não está dando o resultado desejado.

Em um arquivo com muitas linhas, você precisa usar um loop:

while read -r line; do
grep -Eo '[0-9]' <<<"$line" |grep -m1 -E '[0-9]'
done < file.txt

Ou em uma linha de comando:

while read -r line; do grep -Eo '[0-9]' <<<"$line" |grep -m1 -E '[0-9]';done < a.txt

A saída é a desejada.

    
por 14.12.2016 / 10:34
2

Você tem permissão para usar sed ?

$ sed 's/[^[[:digit:]]*\([[:digit:]]\).*//' << EOF
> first 1 is the real 2 time the word matched 3 
> appeared on the previous line but is 4 the fourth.
> Every line can have more numbers 5 because numbers 6 are everywhere
> I need to extract the number just after the word 7 that precedes 8
> EOF
1
4
5
7
    
por 14.12.2016 / 10:03
2

Você poderia usar dois grep comandos, primeiro correspondendo e retornando tudo até a primeira seqüência de dígitos decimais, depois correspondendo e retornando apenas os dígitos:

grep -Eo '^[^0-9]*[0-9]{1,}' file | grep -Eo '[0-9]{1,}'

[NOTA: Estou usando {1,} , já que AFAIK {1} é redundante e estou supondo que você queira combinar sequências decimais.]

Se você tiver permissão para usar o modo PCRE e seu grep oferecer suporte, você poderá fazer a mesma coisa em um único grep , usando a asserção lookbehind \K variable width:

grep -Po '^[^0-9]*\K[0-9]+' file

ou (um pouco mais compactamente, usando o estilo perl \d para um dígito decimal):

grep -Po '^[^\d]*\K\d+' file

Ou, como você não diz que você não pode usar o perl em si, você pode dividir em campos separados por espaço e, em seguida, encontrar o primeiro campo de dígitos:

perl -MList::Util=first -alne 'print first { /^\d+$/ } @F'
    
por 14.12.2016 / 15:06
1

que tal este sed e grep

$ sed "s/\([0-9]\)/\n\n/" input.txt | grep "^.$"
1
4
5
7
    
por 14.12.2016 / 10:16
1

Você pode tentar isso:

grep -Eon ' [0-9]{1}' | sort -k1,1 -u

A saída será a seguinte (não tenho certeza se os números de linha são os disjuntores do negócio):

1: 1
2: 4
3: 5
4: 7

Como alternativa, esta expressão fornecerá a saída desejada:

grep -Eon ' [0-9]{1}' | sort -k1,1 -u | grep -o ' .*'

Saída (sua amostra de saída inclui espaços em branco iniciais):

 1
 4
 5
 7
    
por 14.12.2016 / 10:55