Usando a função bash shell dentro do AWK

É possível usar a função bash dentro do AWK de alguma forma?

Arquivo de exemplo (string, int, int , int)

Mike 247808 247809 247810 

Tentando converter valores de decimal em hexadecimal.

Função definida em .bashrc ou em script de shell.

$ awk "{print $1 ; d2h($2)}" file awk: calling undefined function d2h input record number 1, file file source line number 1 

Resposta

Tente use a função system():

awk "{printf("%s ",$1); system("d2h " $2)}" file 

No seu caso, system irá chame d2h 247808 e anexe a saída desse comando à printf saída:

Mike 3C800 

EDITAR:

Como system usa sh em vez de bash Não consigo encontrar uma maneira de acessar .bashrc. Mas você ainda pode usar funções do seu script bash atual:

#!/bin/bash d2h() { # do some cool conversion here echo "$1" # or just output the first parameter } export -f d2h awk "{printf("%s ",$1); system("bash -c "\""d2h "$2""\""")}" file 

EDITAR 2:

Não sei por que, mas isso não está funcionando no meu Ubuntu 16.04. Isso é estranho, porque costumava funcionar no Ubuntu 14.04.

Comentários

  • Isso poderia funcionar se d2h era um executável, mas não se ‘ sa ” função definida em .bashrc ou em script de shell “.
  • @MichaelHomer sim, você está certo. Graças ao seu comentário, percebi que respondi à pergunta que ninguém perguntou. Mas descobri uma maneira de usar funções do script atual (e possivelmente de outros scripts via source), mas posso ‘ f figura por que não ‘ não funciona com .bashrc.
  • Isso ‘ s também é uma vulnerabilidade de injeção de comando, pois o conteúdo de $2 acaba sendo interpretado como código de shell.
  • Se export -f d2h não ‘ não funciona, você pode fazer como para ksh / zsh: (\ 42 e \ 47 são os códigos de escape para aspas simples e duplas) CODE=$(typeset -f d2h) awk ' { system("bash -c \47eval \42$CODE\42; d2h \42"$2"\42\47") }'

Resposta

Você pode chamar o bash do awk e usar sua saída. Isso é obviamente perigoso do ponto de vista do desempenho se acontecer com muita frequência. Citando a página de manual:

command | getline [var] 

Execute o comando canalizando a saída para $ 0 ou var,

comando seria um script bash que contém a definição da função e executa a função.

Resposta

Converter de decimal em hexadecimal é algo que awk pode muito bem fazer sozinho. E você pode definir uma função awk para fazer isso:

 function d2h(d) { return sprintf("%x", d) }  

Agora, para responder à pergunta no caso geral, awk execute bash funções, você “d precisa awk para executar um bash shell, que bash para interpretar a definição dessa função e chamar essa função, com o valor extraído por awk passado como argumentos.

Não trivial.

bash suporta funções de exportação por meio do ambiente, portanto, está disponível em invocações subsequentes de bash, de modo que é uma maneira de passar a definição da função para o bash invocado por awk:

export -f d2h 

As únicas maneiras de awk executar um comando (bash h aqui) estão com seu system("cmd"), ou print... | "cmd" ou "cmd" | getline. Em todos os casos, awk executa um shell para interpretar que cmd, mas será sh, não bash. Portanto, você precisa construir uma linha de comando para sh que é uma bash invocação que interpreta uma bash linha de comando para invocar a função, então você precisa ter cuidado ao citar:

export -f d2h <file awk -v q=""" " function shquote(s) { gsub(q, q "\\" q q, s) return q s q } {print $1; system("exec bash -c "\""d2h \"$1\""\"" bash " shquote($2))}" 

Se você deseja obter a saída da função de volta para awk, seria necessário transferi-lo de volta por meio de um cano. Para isso, você “d usaria cmd | getline em vez de system(cmd) (que deixa cmd” s stdout intocado).

cmd | getline line armazena uma linha (estritamente falando um registro , registros sendo linhas por padrão), então para obter a saída completa nos casos em que é composta de várias linhas, você precisa de um loop como:

 awk "... cmd = "exec bash -c "\""d2h \"$1\""\"" bash " shquote($2) output = "" while ((cmd | getline line) > 0) { output = output line RS } sub(RS "$", "", output) # remove the last newline ..."  

Isso significa executar um sh e um bash para cada cada invocação da função , por isso será bastante ineficiente. Isso acabaria sendo ainda mais ineficiente do que bash fazer a leitura e a divisão com um while read loop:

(unset -v IFS; while read -r a b rest; do printf "%s\n" "$a" d2h "$b" done < file) 

Observe também que, desde o shellshock, bash agora exporta funções em variáveis de ambiente que são nomeadas como BASH_FUNC_d2h%%. Algumas sh implementações incluindo mksh e versões mais recentes de dash remove essas variáveis de ambiente do ambiente:

$ env "foo%%=bar" dash -c "printenv foo%%" $ env "foo%%=bar" mksh -c "printenv foo%%" $ env "foo%%=bar" zsh -c "printenv foo%%" bar $ env "foo%%=bar" bash -c "printenv foo%%" bar 

Então, em vez de depender do frágil recurso de exportação de função, você poderia passar a definição da função de outra maneira. Pode ser por meio de uma variável de ambiente com um nome usual:

 BASH_FUNCTIONS=$(typeset -f d2h) awk " ... cmd = "exec bash -c "\""eval \"$BASH_FUNCTIONS\";" \ "d2h \"$1\""\"" bash " shquote($2) ..."  

Resposta

Tente fazer isto:

awk "{print $1 ; printf "%x\n", $2}" file 

AFAIK, você não pode usar um bash função no awk, mas apenas um script. Você pode usar uma função awk se necessário.

Resposta

Usando uma função bash definida pelo usuário inside awk

Isenção de responsabilidade: sei que não é isso que o OP está tentando fazer, mas o Google levará outros como eu a essa resposta.

Situação

Você tem um bash script que é organizado com funções (porque você não odeia a si mesmo ou [a maioria] dos colegas de trabalho) e pelo menos 1 dessas funções precisa chame outro de dentro do awk.

Solução

Script

#!/bin/env bash # The main function - it"s a sound pattern even in BASH main(){ # In the awk command I do some tricky things with single quotes. Count carefully... # The first $0 is outside the single quotes so it is the name of the current bash script. # The second $0 is inside the single quotes so it is awk"s current line of input. awk "{printf("%s. ", ++c); system(""$0" --do"); print $0}"<<-PRETEND_THIS_IS_AN_INPUT_STREAM and and well PRETEND_THIS_IS_AN_INPUT_STREAM } # functionized to keep things DRY doit(){ echo -n "doin" it " } # check for a command switch and call different functionality if it is found if [[ $# -eq 1 && $1 == "--do" ]]; then doit else main fi 

Saída

$ ./example.sh 1. doin" it and 2. doin" it and 3. doin" it well 

Comentários

  • eu representa Queens, ela foi criada no Brooklyn

Resposta

Apenas um exemplo rápido para demonstrar @HaukeLaging “s command|getline:

  1. deixe a entrada ser:
Dear friends my name is `id -nu` and today is `date "+%Y-%m-%d"`. 

onde estamos seguindo a sintaxe do shell, na entrada,

`command` 

é usado para denotar comandos embutidos a serem substituídos pelo resultado de sua execução.

  1. Podemos expandir o comando shell embutido por:
#!/usr/bin/gawk -f BEGIN { FS ="`"; } NF==3 { $2 | getline $2 } { print } 
  1. Uso (após o chmod usual):
$ expand-inline input Dear friends my name is jjoao and today is 2018-01-15. 

Resposta

Isso lhe dará boas chances.

cat ../logs/em2.log.1 |grep -i 192.168.21.15 |awk "{system("date"); print $1}" 

a função do sistema permite que você analise o comando bash dentro do fluxo do awk.

Resposta

Esta resposta é para GNU awk, mas outras versões podem implementar o mesmo truque. A ideia é que, desde que o lado direito do cano seja exatamente o mesmo e não saia, o awk não fecha o cano. Mas se for diferente, abrirá um novo tubo. Por exemplo, se você digitar:

awk "BEGIN{ shell= "/bin/bash" } { print $0 | "/bin/bash" } END { print "echo $a" | " /bin/bash" }" 

você pode digitar:

a=5 echo $a 

e obter a resposta esperada (?) 5: nenhum novo shell foi gerado. Mas na seção END, digitei um espaço extra, então o RHS do tubo é diferente, e um novo shell é gerado sem valor para a variável a (e, portanto, imprimirei uma linha em branco na saída. Não consigo encontrar no documentação, mas a maneira recomendada de usar tubos de longo prazo é como eu: coloque o comando na seção BEGIN em uma variável e reutilize essa variável.

Dar uma função definida pelo usuário a uma sessão bash e então, reutilizá-lo é um exercício deixado para o leitor 🙂

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *