Às vezes (em casos simples) é possível ajustar o separador de campos ( FS) e escolher o que se deseja combinar com a $field. A pré-formatação da entrada também pode ajudar.
Aparentemente, alguém discorda. Esta página da web é de 2005: tek-tips.com/faqs.cfm?fid=5674 Confirma que você não pode reutilizar grupos correspondentes no awk.
Peter Tillemans
3
Eu prefiro 'perl -n -p -e ...' em vez de awk para quase todos os casos de uso, pois é mais flexível, mais poderoso e tem uma sintaxe mais saudável na minha opinião.
Peter Tillemans
15
gawk! = awk. São ferramentas diferentes e gawknão estão disponíveis por padrão na maioria dos lugares.
Oli
6
O OP pediu especificamente uma solução awk, então não acho que seja uma resposta.
Joppe
6
@ Joppe, você não pode dar uma solução awk se não houver solução. Na linha 3, explico que o AWK não suporta grupos de captura e dei uma alternativa, que o OP aparentemente apreciou porque essa resposta foi aceita. Como eu poderia responder melhor a essa pergunta?
precisa
335
Com o gawk, você pode usar a matchfunção para capturar grupos entre parênteses.
gawk 'match($0, pattern, ary) {print ary[1]}'
exemplo:
echo "abcdef"| gawk 'match($0, /b(.*)e/, a) {print a[1]}'
saídas cd.
Observe o uso específico do gawk que implementa o recurso em questão.
Para uma alternativa portátil, você pode obter resultados semelhantes com match()e substr.
@ OlleHärstedt Não, não podia. Ele cobre apenas seu caso de uso quando você não possui grupos de captura. Nesse caso, fica feio com os encadeados grep -o.
Ed Morton: isso merece uma resposta de nível superior, eu diria. edit: uhm ... que imprime RewriteRule (.*) http://www.mysite.net/$para mim, que é mais do que o subgrupo.
Você também pode simular a captura no vanilla awk, sem extensões. Não é intuitivo:
Etapa 1. Use o gensub para localizar correspondências com algum caractere que não apareça na sua string. passo 2. Use divisão contra o personagem. Etapa 3. Todos os outros elementos da matriz dividida são o seu grupo de captura.
$ echo 'ab cb ad' | awk '{split (gensub (/ a ./, SUBSEP "e" SUBSEP ", g", US $ 0), cap, SUBSEP); tampa de impressão [2] "|" tampa [4]; } '
ab | ad
Estou quase certo de que gensubé uma gawkfunção específica. O que você obtém do seu awk se digitar awk --version; -?). Boa sorte a todos.
shellter
6
Estou totalmente certo de que o gensub é um gawk-ism, embora o BusyBox awk também o tenha. Essa resposta também poderia ser implementado usando gsub, no entanto:echo 'ab cb ad' | awk '{gsub(/a./,SUBSEP"&"SUBSEP);split($0,cap,SUBSEP);print cap[2]"|"cap[4]}'
dubiousjim
3
gensub () é uma extensão do gawk, o manual do gawk diz claramente isso. Outras variantes do awk também podem implementá-lo, mas ainda não é o POSIX. Tente gawk --posix '{gsub (...)}' e ele irá reclamar
MestreLion
2
@MestreLion, você quer dizer que vai reclamar gawk --posix '{gensub(...)}'.
dubiousjim
1
Apesar de você estar errado sobre o POSIX awk ter a gensubfunção, seu exemplo se aplica a um cenário muito limitado: todo o padrão é agrupado, não pode corresponder a algo como tudo key=(value)quando quero extrair apenas as valuepartes.
Meow
2
Eu lutei um pouco com a criação de uma função bash que envolva a resposta de Peter Tillemans, mas aqui está o que eu vim com:
função regex {perl -n -e "/ $ 1 / && printf \"% s \ n \ "," '$ 1'}
Achei que isso funcionou melhor do que a função bash do opsb para o seguinte argumento de expressão regular, porque não quero que o "ms" seja impresso.
Eu prefiro essa solução, pois você pode ver as partes do grupo que delimitam a captura e também as omite. No entanto, alguém poderia explicar como isso funciona? Não consigo fazer com que essa sintaxe perl funcione corretamente no BASH, porque não a entendo muito bem - especialmente as aspas duplas / aspas simples$1
Demis
Não é algo que eu tenha feito antes ou depois, mas olhando para trás, o que está fazendo é concatenar duas cadeias de caracteres, sendo a primeira entre aspas duplas (essa primeira sequência contém aspas duplas incorporadas escapadas com barra invertida) e a segunda entre aspas simples . Então o resultado dessa concatenação é fornecido como argumento para perl -e. Além disso, você precisa saber que o primeiro $ 1 (aquele entre aspas duplas) é substituído pelo primeiro argumento da função, enquanto o segundo $ 1 (aquele entre aspas simples) é deixado intocado. Veja este exemplo
wytten
Entendo, isso está fazendo um pouco mais de sentido agora. Então, onde no comando perl está a definição de captura de grupo / grupo de expressão regular? Vejo que você escreveu '([0-9]*)ms$'- isso é fornecido como argumento (e a string, outro argumento)? E a saída de perl -eestá sendo inserida no printfcomando do bash, então, para substituir %s, está certo? Obrigado, espero usar isso.
Demis
1
Você passa uma expressão regular entre aspas simples como o único argumento para a função regex bash. Exemplo
FS
) e escolher o que se deseja combinar com a$field
. A pré-formatação da entrada também pode ajudar.gawk
(uma vez que usagensub
).Respostas:
Esse foi um passeio pela estrada da memória ...
Substituí awk por perl há muito tempo.
Aparentemente, o mecanismo de expressão regular do AWK não captura seus grupos.
você pode considerar usar algo como:
o sinalizador -n faz com que o perl faça um loop sobre todas as linhas, como o awk.
fonte
gawk
! =awk
. São ferramentas diferentes egawk
não estão disponíveis por padrão na maioria dos lugares.Com o gawk, você pode usar a
match
função para capturar grupos entre parênteses.exemplo:
saídas
cd
.Observe o uso específico do gawk que implementa o recurso em questão.
Para uma alternativa portátil, você pode obter resultados semelhantes com
match()
esubstr
.exemplo:
saídas
cd
.fonte
Isso é algo que eu preciso o tempo todo, então criei uma função bash para isso. É baseado na resposta de Glenn Jackman.
Definição
Adicione isso ao seu .bash_profile etc.
Uso
Capturar regex para cada linha no arquivo
Capturar o primeiro grupo de captura de regex para cada linha no arquivo
fonte
grep -o
?grep -o
grupos capturados?grep -o
.Você pode usar o GNU awk:
fonte
awk 'match($0, /.*(http.*?)\$/) { print substr($0,RSTART,RLENGTH) }'
RewriteRule (.*) http://www.mysite.net/$
para mim, que é mais do que o subgrupo.RSTART
eRLENGTH
referem-se a substring correspondida pelo padrãoVocê também pode simular a captura no vanilla awk, sem extensões. Não é intuitivo:
Etapa 1. Use o gensub para localizar correspondências com algum caractere que não apareça na sua string. passo 2. Use divisão contra o personagem. Etapa 3. Todos os outros elementos da matriz dividida são o seu grupo de captura.
fonte
gensub
é umagawk
função específica. O que você obtém do seu awk se digitarawk --version
; -?). Boa sorte a todos.echo 'ab cb ad' | awk '{gsub(/a./,SUBSEP"&"SUBSEP);split($0,cap,SUBSEP);print cap[2]"|"cap[4]}'
gawk --posix '{gensub(...)}'
.gensub
função, seu exemplo se aplica a um cenário muito limitado: todo o padrão é agrupado, não pode corresponder a algo como tudokey=(value)
quando quero extrair apenas asvalue
partes.Eu lutei um pouco com a criação de uma função bash que envolva a resposta de Peter Tillemans, mas aqui está o que eu vim com:
Achei que isso funcionou melhor do que a função bash do opsb para o seguinte argumento de expressão regular, porque não quero que o "ms" seja impresso.
fonte
$1
'([0-9]*)ms$'
- isso é fornecido como argumento (e a string, outro argumento)? E a saída deperl -e
está sendo inserida noprintf
comando do bash, então, para substituir%s
, está certo? Obrigado, espero usar isso.