
É 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 para hexadecimal.
Função definida em .bashrc
ou em shell script.
$ awk '{print $1 ; d2h($2)}' file
awk: calling undefined function d2h
input record number 1, file file
source line number 1
Responder1
Tente usar system()
a função:
awk '{printf("%s ",$1); system("d2h " $2)}' file
No seu caso system
, chamará d2h 247808
e anexará a saída deste comando à printf
saída:
Mike 3C800
EDITAR:
Como system
usa sh
em vez de bash
não consigo encontrar uma maneira de acessar o arquivo .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
Nota: -f
é usado paraexportar uma funçãoem vez de uma variável.
EDITAR 2:
Não sei por que, mas isso não está funcionando no meu Ubuntu 16.04. Isso é estranho, porque funcionava no Ubuntu 14.04.
Responder2
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.
Responder3
Converter de decimal para hexadecimal é algo que awk
pode muito bem ser feito sozinho. E você poderia definir umawk
função para fazer isso:
function d2h(d) {
return sprintf("%x", d)
}
Agora, para responder à pergunta no caso geral, para awk
executar bash
funções, você precisaria awk
executar um bash
shell, para bash
interpretar a definição daquela função, e chamar essa função, com o valor extraído awk
passado como argumentos.
Não é trivial.
bash
suporta a exportação de funções através do ambiente, portanto está disponível em invocações subsequentes de bash
, então essa é 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
aqui) são com seu system("cmd")
, ou print... | "cmd"
ou "cmd" | getline
. Em todos os casos, awk
executa um shell para interpretar isso cmd
, mas será sh
, não bash
. Portanto, você precisa construir uma linha de comando, pois sh
é uma bash
invocação que interpreta uma bash
linha de comando para invocar a função, portanto, 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ê quiser recuperar a saída da função awk
, precisará transferi-la de volta por meio de um canal. Para isso, você usaria cmd | getline
em vez de system(cmd)
(o que deixa cmd
o stdout intocado).
cmd | getline line
lojasuma linha(estritamente falandoum registro, os registros são linhas por padrão), portanto, para obter a saída completa nos casos em que ela é composta por várias linhas, você precisaria 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 invocação da função, portanto será bastante ineficiente. Isso acabaria sendo ainda significativamente mais ineficiente do que fazer bash
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 denominadas como BASH_FUNC_d2h%%
. Algumas sh
implementações, incluindo mksh
versões mais recentes dedash
removeressas 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
Portanto, em vez de confiar no frágil recurso de exportação de função, você poderia passar a definição da função de outra maneira. Poderia ser através 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)
...'
Responder4
Usando uma função bash definida pelo usuário dentro do 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 organizado com funções (porque você não odeia a si mesmo ou à [maioria] dos colegas de trabalho) e pelo menos uma dessas funções precisa chamar outra de dentro do awk
.
Solução
Roteiro
#!/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