É 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
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
:
- 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.
- Podemos expandir o comando shell embutido por:
#!/usr/bin/gawk -f BEGIN { FS ="`"; } NF==3 { $2 | getline $2 } { print }
- 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 🙂
d2h
era um executável, mas não se ‘ sa ” função definida em .bashrc ou em script de shell “.source
), mas posso ‘ f figura por que não ‘ não funciona com.bashrc
.$2
acaba sendo interpretado como código de shell.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") }'