grep
vem depois do comando g/re/p
ed
. Seu objetivo principal é imprimir as linhas que correspondem a um regexp. Não é seu papel editar o conteúdo dessas linhas. Você tem sed
(o editor de fluxo) ou awk
para isso.
Agora, algumas implementações de grep
, começando com GNU grep
, adicionaram uma opção -o
para imprimir a parte correspondente de cada linha (o que é correspondido pelo regexp, não por seus grupos de captura). Você tem alguma implementação de grep
como o GNU novamente (com -P
) ou pcregrep
que suportam PCREs para seus regexps.
pcregrep
na verdade adicionou uma opção -o<n>
para imprimir o conteúdo de um grupo de captura. Então você poderia fazer:
pcregrep -o1 -o2 --om-separator=' ' '.zoo.(\d+).*:\s+(.*)'
Mas aqui, a solução padrão óbvia é usar sed
:
sed -n 's/^.*\.zoo\.\([0-9]\{1,\}\).*:[[:space:]]\{1,\}/ /p'
Ou se você quiser regexps perl, use perl:
perl -lne 'print "$1 $2" if /\.zoo\.(\d+).*:\s+(.*)/'
Com o GNU grep
, se você não se importa que as correspondências apareçam em linhas diferentes, você pode fazer:
$ grep -Po '\.zoo\.\K\d+|:\s+\K.*' < file
2
0.45654343
Observe que, embora \K
redefina o início da parte correspondente, isso não significa que você pode se safar com as duas partes da sobreposição da alternância.
grep -Po '.zoo.(\K\d+|.: \K.)'
não funcionaria, assim como echo foobar | grep -Po 'foo|foob'
não funcionaria (ao imprimir foo
e foob
). foo|foob
corresponde pela primeira vez foo
e, em seguida, grep
procura outras possíveis correspondências na entrada após o foo
, começando assim em b
de bar
, por isso não é possível encontrar mais depois disso. / p>
Acima, com grep -Po '\.zoo\.\K\d+|:\s+\K.*'
, procuramos apenas :<spaces><anything>
na segunda parte da alternância. Isso corresponde na parte que está após .zoo.<digits>
, mas isso também significa que eles encontrarão esses :<spaces><anything>
em qualquer lugar na entrada, não apenas quando eles seguirem .zoo.<digits>
.
Existe uma maneira de contornar isso, usando outro operador especial PCRE: \G
. \G
corresponde no início do assunto. Para uma única correspondência, isso equivale a ^
, mas com várias correspondências (pense em sed
/ perl
g
sinalizador em s/.../.../g
) como com -o
onde grep
tenta encontrar todos as partidas na linha, que também coincidem após o final da partida anterior. Então, se você fizer isso:
grep -Po '\.zoo\.\K\d+|(?!^)\G.*:\s+\K.*'
Em que (?!^)
é um operador de look-ahead negativo que significa não no início da linha , que \G
corresponderá somente após uma correspondência anterior bem-sucedida (não vazia) .*:\s+\K.*
corresponderá apenas se seguir uma correspondência anterior com sucesso, e isso só pode ser o .foo.<digits>
um, já que a outra parte da alternação corresponde ao final da linha.
Em uma entrada como:
.zoo.1.zoo.2 tar: blah
Isso produziria:
1
2
blah
Embora. Se você não quisesse, também desejaria que a primeira parte da alternação correspondesse apenas no início da linha. Algo como
grep -Po '^.*?\.zoo\.\K\d+|(?!^)\G.*:\s+\K.*'
Isso ainda gera 2
em uma entrada como .zoo.2 no colon character
ou .zoo.2 blah:
. Que você poderia contornar com um operador de look-ahead na primeira parte da alternância, e procurar pelo menos um não-espaço após :<spaces>
(e também usando $
para evitar problemas com não-caracteres)
grep -Po '^.*?\.zoo\.\K\d+(?=.*:\s+\S.*$)|(?!^)\G.*:\s+\K\S.*$'
Você provavelmente precisaria de algumas páginas de comentários para explicar esse regexp, então eu ainda iria para a linha reta sed
/ perl
solutions ...