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 ...