¿Es posible usar la función bash dentro de AWK de alguna manera?
Archivo de ejemplo (string, int, int , int)
Mike 247808 247809 247810
Intentando convertir valores de decimal a hexadecimal.
Función definida en .bashrc
o en un script de shell.
$ awk "{print $1 ; d2h($2)}" file awk: calling undefined function d2h input record number 1, file file source line number 1
Responder
Intente use la función system()
:
awk "{printf("%s ",$1); system("d2h " $2)}" file
En su caso, system
llamar a d2h 247808
y luego agregar la salida de este comando a la printf
salida:
Mike 3C800
EDITAR:
Como system
usa sh
en lugar de bash
No puedo encontrar una manera de acceder a .bashrc
. Pero aún puede usar funciones de su 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
EDICIÓN 2:
No lo sé por qué, pero esto no funciona en mi Ubuntu 16.04. Esto es extraño, porque solía funcionar en Ubuntu 14.04.
Comentarios
Responder
Puede llamar a bash desde awk y usar su salida. Eso es obviamente peligroso desde la perspectiva del desempeño si ocurre con demasiada frecuencia. Citando la página del 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.
Respuesta
Convertir de decimal a hexadecimal es algo que awk
puede hacer muy bien por sí mismo. Y podría definir una función awk
para hacerlo:
function d2h(d) { return sprintf("%x", d) }
Ahora, para responder a la pregunta en el caso general, awk
para ejecutar bash
funciones, «necesitarías awk
para ejecutar un bash
shell, que bash
para interpretar la definición de esa función, y llamar a esa función, con el valor extraído por awk
pasado como argumentos.
No es 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 es una forma de pasar la definición de la función a la bash
invocada por awk
:
export -f d2h
Las únicas formas de que awk
ejecute un comando (bash
h ere) son con su system("cmd")
, o print... | "cmd"
o "cmd" | getline
. En todos los casos, awk
ejecuta un shell para interpretar que cmd
, pero será sh
, no bash
. Por lo tanto, debe construir una línea de comando para sh
que sea una invocación bash
que interprete una bash
línea de comando para invocar la función, por lo que debe tener cuidado con las comillas:
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 obtener la salida de la función de nuevo en awk
, necesitaría transferirlo de nuevo a través de una tubería. Para eso, «usaría cmd | getline
en lugar de system(cmd)
(que deja la salida estándar de cmd
» sin tocar).
cmd | getline line
almacena una línea (estrictamente hablando un registro , los registros son líneas por defecto), así que para obtener el resultado completo en los casos en que esté formado por varias líneas, necesitará 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 una sh
y una bash
para cada invocación de la función , por lo que va a ser bastante ineficiente. Eso terminaría siendo significativamente más ineficiente que tener bash
haciendo la lectura y dividiendo 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 que se denominan BASH_FUNC_d2h%%
. Algunas sh
implementaciones, incluidas mksh
y versiones más recientes de dash
eliminar esas 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 depender de la endeble función de exportación de funciones, podría pasar la definición de función de alguna otra manera. Podría ser a través de 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) ..."
Responder
Intenta hacer esto:
awk "{print $1 ; printf "%x\n", $2}" file
AFAIK, no puedes usar un bash función en awk pero solo un script. Puede usar una función awk si es necesario.
Responder
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 está tratando de hacer, pero Google llevará 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 debe llamar a otro desde awk
.
Solución
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
Salida
$ ./example.sh 1. doin" it and 2. doin" it and 3. doin" it well
Comentarios
- yo representar a Queens, se crió en Brooklyn
Responder
Solo un ejemplo rápido para demostrar @HaukeLaging «s command|getline
:
- sea la entrada:
Dear friends my name is `id -nu` and today is `date "+%Y-%m-%d"`.
donde estamos siguiendo la sintaxis de shell, en la entrada,
`command`
se usa para denotar comandos en línea para ser reemplazados por el resultado de su ejecución.
- Podemos expandir el comando de shell en línea mediante:
#!/usr/bin/gawk -f BEGIN { FS ="`"; } NF==3 { $2 | getline $2 } { print }
- Uso (después del chmod habitual):
$ expand-inline input Dear friends my name is jjoao and today is 2018-01-15.
Respuesta
Esto le dará buenas oportunidades.
cat ../logs/em2.log.1 |grep -i 192.168.21.15 |awk "{system("date"); print $1}"
La función del sistema le permite analizar el comando bash dentro del flujo awk.
Respuesta
Esta respuesta es para GNU awk, pero otras versiones pueden implementar el mismo truco. La idea es que mientras el lado derecho de la tubería sea exactamente el mismo y no salga, awk no cerrará la tubería. Pero si es diferente, abrirá una nueva tubería. Por ejemplo, si escribe:
awk "BEGIN{ shell= "/bin/bash" } { print $0 | "/bin/bash" } END { print "echo $a" | " /bin/bash" }"
puede escribir:
a=5 echo $a
y obtenga la respuesta esperada (?) 5: no se generó un nuevo shell. Pero en la sección END, escribí un espacio adicional, por lo que el RHS de la tubería es diferente, y se genera un nuevo shell sin valor para la variable a (y por lo tanto imprimirá una línea en blanco al salir. No puedo encontrarlo en documentación, pero la forma recomendada de usar tuberías a largo plazo es la que tengo: poner el comando en la sección BEGIN en una variable y reutilizar esa variable.
Dar una función definida por el usuario a una sesión de bash y luego, reutilizarlo es un ejercicio que le queda al lector 🙂
d2h
eran ejecutables, pero no si eran ‘ una función » definida en .bashrc o en un script de shell «.source
) pero puedo ‘ f figure averiguar por qué no ‘ no funciona con.bashrc
.$2
termina siendo interpretado como código de shell.export -f d2h
doesn ‘ t funciona, puede hacerlo como para ksh / zsh: (\ 42 y \ 47 son los códigos de escape para comillas simples y dobles)CODE=$(typeset -f d2h) awk ' { system("bash -c \47eval \42$CODE\42; d2h \42"$2"\42\47") }'