Usando vários delimitadores no awk


202

Eu tenho um arquivo que contém as seguintes linhas:

/logs/tc0001/tomcat/tomcat7.1/conf/catalina.properties:app.env.server.name = demo.example.com
/logs/tc0001/tomcat/tomcat7.2/conf/catalina.properties:app.env.server.name = quest.example.com
/logs/tc0001/tomcat/tomcat7.5/conf/catalina.properties:app.env.server.name = www.example.com

Na saída acima, quero extrair 3 campos (número 2, 4 e o último *.example.com). Estou recebendo a seguinte saída:

cat file | awk -F'/' '{print $3 "\t" $5}'
tc0001   tomcat7.1
tc0001   tomcat7.2
tc0001   tomcat7.5

Como também extraio o último campo com o nome de domínio que é posterior '='? Como uso multiple delimiterpara extrair o campo?


2
Responder à minha pergunta, que é a mesma, mas diferente, awkfoi engolir campos quando estavam em branco, o que prejudicou a numeração dos campos. Mudei -F " "para -F "[ ]"e awknão engoli mais os campos vazios.
Adam

Respostas:


324

O delimitador pode ser uma expressão regular.

awk -F'[/=]' '{print $3 "\t" $5 "\t" $8}' file

Produz:

tc0001   tomcat7.1    demo.example.com  
tc0001   tomcat7.2    quest.example.com  
tc0001   tomcat7.5    www.example.com

42
Claro, catprocesso não é necessária: awk '...' file. Além disso, seria mais arrumado para usar o separador de campo de saída:awk -F'[/=]' -v OFS="\t" '{print $3, $5, $8}'
Glenn Jackman

17
Os delimitadores awk podem ser expressões regulares ... isso fez o meu dia!
precisa saber é o seguinte

4
@ das.cyklone: ​​awk também pode ter vários separadores, com |: ex: awk -F 'this|that|[=/]' '......' (útil para ter palavras / sequências que separam as coisas) (observe que isso mantém os espaços nos campos entre 2 separadores. A adição também |[ \t]+pode ser útil, mas pode fazer coisas complicado ... como muitas vezes há espaços antes e depois 'isto', isso vai fazer 2 campo vazio extra de aparecer em entre o espaço (s) e 'isto')
Olivier Dulac

Eu tentei isso em duas distros diferentes e recebo o mesmo comportamento: quero obter a porta do netstat -ntpl "netstat -ntpl | sed 's /: / /' 'awk' {print $ 5} '" funciona, mas poderia fazer sem doulbe piping Isso funciona, mas eu não esperava os dados no campo 17: "netstat -ntpl | awk -F" |: "'{print $ 17}'"
louigi600

2
sim ... isso me deu o que eu queria: awk -F "[:] +" '/ \ / postmaster * $ / {print $ 5}'
louigi600 11-17

44

Boas notícias! awkO separador de campos pode ser uma expressão regular. Você só precisa usar -F"<separator1>|<separator2>|...":

awk -F"/|=" -vOFS='\t' '{print $3, $5, $NF}' file

Devoluções:

tc0001  tomcat7.1  demo.example.com
tc0001  tomcat7.2  quest.example.com
tc0001  tomcat7.5  www.example.com

Aqui:

  • -F"/|="define o separador do campo de entrada como /ou =. Em seguida, define o separador do campo de saída como uma guia.

  • -vOFS='\t'está usando o -vsinalizador para definir uma variável. OFSé a variável padrão para o separador de campos de saída e é definida como o caractere de tabulação. A bandeira é necessária porque não há um built-in para o OFS como -F.

  • {print $3, $5, $NF} imprime os terceiro, quinto e último campos com base no separador de campos de entrada.


Veja outro exemplo:

$ cat file
hello#how_are_you
i#am_very#well_thank#you

Este arquivo possui dois separadores de campos #e _. Se quisermos imprimir o segundo campo, independentemente de o separador ser um ou outro, vamos fazer com que ambos sejam separadores!

$ awk -F"#|_" '{print $2}' file
how
am

Onde os arquivos são numerados da seguinte maneira:

hello#how_are_you           i#am_very#well_thank#you
^^^^^ ^^^ ^^^ ^^^           ^ ^^ ^^^^ ^^^^ ^^^^^ ^^^
  1    2   3   4            1  2   3    4    5    6

1
Obrigado @BUFU pela sua edição. Eu removi a referência OFS para focar apenas na parte FS, mas também é bom tê-la. Felicidades!
fedorqui 'SO stop prejudicar'

5

Se seu espaço em branco for consistente, você poderá usá-lo como um delimitador, também em vez de inserir \tdiretamente, você poderá definir o separador de saída e ele será incluído automaticamente:

< file awk -v OFS='\t' -v FS='[/ ]' '{print $3, $5, $NF}'

3

Para um campo de separação de qualquer número 2através 5ou carta aou #ou um espaço, em que o personagem de separação devem ser repetidos pelo menos 2 vezes e não mais do que 6 vezes, por exemplo:

awk -F'[2-5a# ]{2,6}' ...

Tenho certeza de que existem variações disso usando () e parâmetros


3

One-liner Perl:

perl -F'/[\/=]/' -lane 'print "$F[2]\t$F[4]\t$F[7]"' file

Essas opções de linha de comando são usadas:

  • -nfaça um loop em todas as linhas do arquivo de entrada, coloque a linha na $_variável, não imprima automaticamente todas as linhas

  • -l remove as novas linhas antes do processamento e as adiciona novamente depois

  • -amodo de divisão automática - o perl dividirá automaticamente as linhas de entrada na @Fmatriz. O padrão é dividir em espaço em branco

  • -Fmodificador de divisão automática, neste exemplo se divide em um /ou=

  • -e executar o código perl

Perl está intimamente relacionado ao awk, no entanto, a @Fmatriz de divisão automática inicia no índice $F[0]enquanto os campos do awk começam com $ 1.


2

Outra é usar a opção -F, mas passe-a regex para imprimir o texto entre parênteses esquerdo e / direito ().

O conteúdo do arquivo:

528(smbw)
529(smbt)
530(smbn)
10115(smbs)

O comando:

awk -F"[()]" '{print $2}' filename

resultado:

smbw
smbt
smbn
smbs

Usando o awk para imprimir apenas o texto entre []:

Use, awk -F'[][]' mas awk -F'[[]]'não funcionará.

http://stanlo45.blogspot.com/2020/06/awk-multiple-field-separators.html


Sua resposta surgiu na fila de exclusão, porque 9 em cada 10 usuários com 1 reputação vinculados ao próprio blog geralmente são spam. Mas a sua é a exceção à regra. Nos últimos 10 anos de conteúdo, há uma mina de ouro, espero que você tenha um plano para imortalizá-la.
Eric Leschinski

0

Vejo muitas respostas perfeitas no quadro, mas ainda gostaria de enviar meu código também,

awk -F"/" '{print $3 " " $5 " " $7}' sam | sed 's/ cat.* =//g'


2
print $3 " " $5 " " $7pode ser impresso como print $3, $5, $7. Além disso, não vejo a vantagem de usar o awk e depois canalizá-lo para o sed. Em geral, o awk pode ser suficiente e outras respostas mostram isso.
fedorqui 'Então pare de prejudicar'
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.