
¿Es posible utilizar la función bash dentro de AWK de alguna manera?
Archivo de ejemplo (cadena, int, int, int)
Mike 247808 247809 247810
Intentando convertir valores de decimal a hexadecimal.
Función definida en .bashrc
o en el script de shell.
$ awk '{print $1 ; d2h($2)}' file
awk: calling undefined function d2h
input record number 1, file file
source line number 1
Respuesta1
Intente utilizar system()
la función:
awk '{printf("%s ",$1); system("d2h " $2)}' file
En su caso, system
llamará d2h 247808
y luego agregará la salida de este comando a printf
la salida:
Mike 3C800
EDITAR:
Como system
usos sh
en lugar de bash
no encuentro la manera de acceder .bashrc
. Pero aún puedes usar funciones de tu script bash actual:
#!/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
se utiliza paraexportar una funciónen lugar de una variable.
EDITAR 2:
No sé por qué, pero esto no funciona en mi Ubuntu 16.04. Esto es extraño, porque solía funcionar en Ubuntu 14.04.
Respuesta2
Puedes llamar a bash desde awk y usar su salida. Obviamente, esto es peligroso desde una perspectiva de rendimiento si sucede con demasiada frecuencia. Citando la página de manual:
command | getline [var]
Ejecute el comando canalizando la salida a $0 o var,
El comando sería un script bash que contiene la definición de la función y ejecuta la función.
Respuesta3
La conversión de decimal a hexadecimal es algo que awk
muy bien puede hacerse por sí solo. Y podrías definir unawk
función para hacerlo:
function d2h(d) {
return sprintf("%x", d)
}
Ahora, para responder a la pregunta en el caso general, para awk
ejecutar bash
funciones, necesitaría awk
ejecutar un bash
shell, que bash
interpretaría la definición de esa función y llamaría a esa función, con el valor extraído awk
pasado como argumentos.
No trivial.
bash
admite la exportación de funciones a través del entorno, por lo que está disponible en invocaciones posteriores de bash
, por lo que esa es una forma de pasar la definición de la función al bash
invocado por awk
:
export -f d2h
Las únicas formas de awk
ejecutar un comando ( bash
aquí) son con su system("cmd")
o print... | "cmd"
o "cmd" | getline
. En todos los casos, awk
se ejecuta un shell para interpretar eso cmd
, pero así será sh
, no bash
. Entonces necesitas construir una línea de comando porque sh
es una bash
invocación que interpreta una bash
línea de comando para invocar la función, por lo que debes tener cuidado al 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))}'
Si desea recuperar la salida de la función awk
, deberá transferirla nuevamente a través de una tubería. Para eso, usarías cmd | getline
en lugar de system(cmd)
(lo que deja cmd
la salida estándar intacta).
cmd | getline line
historiasuna línea(estrictamente hablandoun registro, los registros son líneas de forma predeterminada), por lo que para obtener el resultado completo en los casos en que esté formado por varias líneas, necesitaría un bucle 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
...'
Eso significa ejecutar uno sh
y otro bash
para cada invocación de la función, por lo que será bastante ineficiente. Eso terminaría siendo incluso significativamente más ineficiente que tener bash
que leer y dividir con un while read loop
:
(unset -v IFS; while read -r a b rest; do
printf '%s\n' "$a"
d2h "$b"
done < file)
También tenga en cuenta que desde Shellshock, bash
ahora exporta funciones en variables de entorno con nombres como BASH_FUNC_d2h%%
. Algunas sh
implementaciones que incluyen mksh
versiones más recientes dedash
eliminaresas variables de entorno del entorno:
$ 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
Entonces, en lugar de confiar en la endeble función de exportación de funciones, podría pasar la definición de la función de otra manera. Podría ser mediante una variable de entorno con un nombre habitual:
BASH_FUNCTIONS=$(typeset -f d2h) awk '
...
cmd = "exec bash -c '\''eval \"$BASH_FUNCTIONS\";" \
"d2h \"$1\"'\'' bash " shquote($2)
...'
Respuesta4
Usando una función bash definida por el usuario dentro de awk
Descargo de responsabilidad:Me doy cuenta de que esto no es lo que el OP intenta hacer, pero Google guiará a otros como yo a esta respuesta.
Situación
Tienes un bash
script que está organizado con funciones (porque no te odias a ti mismo ni a [la mayoría de] tus compañeros de trabajo) y al menos una de esas funciones necesita llamar a otra desde dentro awk
.
Solución
Guion
#!/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
Producción
$ ./example.sh
1. doin' it and
2. doin' it and
3. doin' it well