Como encadear instruções de impressão do awk?

5

Ok, aqui está um exemplo rápido; me isolando o IPV4 de um host em três etapas:

ip -br a  
lo               UNKNOWN        127.0.0.1/8 ::1/128 
eth0             DOWN           
wlan0            UP             192.168.0.101/24 fe80::9fcd:45fb:1e0f:a1cc/64 
ip -br a | awk '/wlan0/ {print $3}'  
192.168.0.101/24
ip -br a | awk '/wlan0/ {print $3}' | awk -F '/' '{print $1}'
192.168.0.101

Em vez de invocar uma segunda instância de awk (direcionando a saída de uma para a próxima); como pode ser feito de uma só vez?

Só queria dizer: a pergunta não é sobre a análise da saída de ip . Eu só precisava de um exemplo rápido para ajudar a ilustrar a pergunta; esta foi a primeira coisa que eu fiz. A questão real é resumida no título.

De qualquer forma, vale a pena (vou ter que verificar, mas tenho certeza); isto é o que eu fiz no passado (recente):

ip -br a s dev wlan0 | awk -F '[ /]*' '{print $3}'
192.168.0.101
    
por tjt263 14.01.2018 / 04:22

5 respostas

2

Você pode usar o gsub para isso:

ip -br a | awk '/wlan0/ {gsub(/\/.*/, ""); print $3}'
    
por 14.01.2018 / 04:37
2

Basta alterar a definição de separador de campo para incluir os dois espaços e / :

$ ip -br a | awk -F'[[:blank:]/]+' '/wlan0/{print $3}'
192.168.0.101

A opção -F'[[:blank:]/]+' diz ao awk para usar qualquer combinação de espaços em branco, tabulações ou barras como o separador de campo na entrada.

    
por 14.01.2018 / 05:00
2

Para essa instância, a maneira mais fácil de fazer isso provavelmente é definir vários separadores usando um regex:

ip -br a | awk -F '[\t /]*' '/wlan0/ {print$3}'

Isso torna o separador de campos qualquer string de / , espaços ou tabulações e, em seguida, imprime o terceiro campo.

Para fazer qualquer arbitrário dois comandos que você gostaria, você praticamente precisa aprender a linguagem de programação awk completa. Eu recomendaria contra isso - tenho certeza de que você tem coisas melhores para fazer com seu tempo.

    
por 14.01.2018 / 05:01
2

Embora as outras respostas resolvam o problema subjacente, elas realmente não respondem à pergunta: "Como faço para encadear declarações de impressão do awk?"

Para esse tipo de problema, a resposta é: "Você não faz isso". Você usa o restante da linguagem para manipular a fonte até obter o resultado desejado - que é o que as outras duas respostas fazem. Você usa somente print para gerar o resultado final.

Depois de especificar um padrão de intervalo inicial como /wlan0/ (ou /^wl/ no meu caso porque meu WiFi tem um nome diferente), sua ação, o código dentro de {} , só funcionará em linhas de entrada contém essa string.

Depois disso, você pode fazer o que precisar com essa linha de entrada.

ip -br a | \
awk '
/^wl/ {
  ip1 = $3
  gsub(/\/.*/, "", ip1)
  print ip1
}
'

Esse código pega o campo desejado, coloca-o em uma variável, edita o conteúdo dessa variável e imprime-o.

A outra resposta faz a mesma coisa com mais eficiência, mas isso ilustra um caso mais geral em que outras etapas podem ser adicionadas. Você pode até salvar o resultado para usar mais tarde com algo encontrado em outra linha de entrada, etc.

Para algo que pode realmente parecer mais com "encadeamento de impressão", o awk tem uma função sprintf() que pode fazer uma impressão formatada de sua entrada em uma variável para processamento posterior.

Ou, se você estiver imprimindo mais de uma coisa em uma linha, seu código pode usar várias declarações printf() sem uma nova linha até a última para criar uma linha de saída peça por peça.

    
por 16.01.2018 / 05:15
0

Isso é um pouco no espírito de A resposta de Stephen Rauch e A resposta de Joe , mas melhor:

awk '/wlan0/ {split($3, a, "/"); print a[1]}'

Isso leva o terceiro campo ( $3 ) e split s, usando / como o separador. Os componentes entram no array a e o número de subcampos é retornado. (Neste fragmento, estou ignorando o valor de retorno.) Portanto, a[1] é o primeiro subcampo / -delimited do terceiro campo.

Isso é mais facilmente generalizado do que as outras respostas. Por exemplo, se sua entrada for

Once upon a midnight dreary, while I pondered, weak and weary,
Over many a quaint and curious volume of forgotten lore—
wlan0 foo/bar the/quick/brown/fox/jumps/over/the lazy/dog
While I nodded, nearly napping, suddenly there came a tapping,
As of some one gently rapping—rapping at my chamber door.

então o comando

awk '/wlan0/ {if (split($3, a, "/") < 4) print "There is no fourth subfield";
                                    else print "The fourth subfield is", a[4]}'

imprimirá o quarto subcampo do terceiro campo da terceira linha ( fox ), depois de verificar o valor de retorno de split para verificar que existem (pelo menos) quatro subcampos. Ou seja, isso é como

awk '/wlan0/ {print $3}' | awk -F '/' '{print $4}'

em um único comando awk , com verificação de erros.

    
por 21.01.2018 / 04:30