Uso de la función bash shell dentro de AWK

24

¿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 script de shell.

awk '{print $1 ; d2h($2)}' file

awk: llamar a la función indefinida d2h entrada número de registro 1, número de línea de origen del archivo de archivo 1

minúsculo
fuente

Respuestas:

27

Intenta usar la system()función:

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

En su caso system, llamará d2h 247808y luego agregará la salida de este comando a la printfsalida:

Mike 3C800

EDITAR:

Como systemusos en shlugar de bashno puedo encontrar una manera de acceder .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

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.

akarilimano
fuente
Esto podría funcionar si d2hfuera un ejecutable, pero no si es una "función definida en .bashrc o en script de shell".
Michael Homer
@ MichaelHomer sí, tienes razón. Gracias a tu comentario me di cuenta de que he respondido la pregunta que nadie hizo. Pero he encontrado una manera de usar funciones del script actual (y posiblemente de otros scripts a través de source), pero no puedo entender por qué no funciona .bashrc.
akarilimano
2
Esa también es una vulnerabilidad de inyección de comandos, ya que el contenido $2termina siendo interpretado como código shell.
Stéphane Chazelas
8

Puede llamar a bash desde awk y usar su salida. Obviamente, eso es peligroso desde una perspectiva de rendimiento si sucede con demasiada frecuencia. Citando la página del manual:

command | getline [var]

Ejecute el comando canalizando la salida en $ 0 o var,

El comando sería un script bash que contiene la definición de la función y ejecuta la función.

Hauke ​​Laging
fuente
Hauke ​​Laging, ¡genial!
JJoao
Lo he usado muchas veces y funciona bien.
Dave Rix
4

Intenta hacer esto:

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

AFAIK, no puedes usar una función bash en awk sino solo un script. Puede usar una función awk si es necesario.

Gilles Quenot
fuente
3

Usar una función bash definida por el usuario dentro de awk

Renuncia: 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

Tiene un bashscript que está organizado con funciones (porque no se odia a sí mismo ni a [la mayoría] de los compañeros de trabajo) y al menos 1 de esas funciones necesita llamar a otra desde dentro awk.

Solución

Guión

#!/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
Bruno Bronosky
fuente
Represento a Queens, fue criada en Brooklyn
Bruno Bronosky
3

awkpuede ejecutar awkfunciones. Para que ejecute bashfunciones, necesitaría awkejecutar un bashshell, que bashinterprete la definición de esa función, y llame a esa función, con el valor extraído por awkpasado como argumentos.

No es trivial

bashadmite la exportación de funciones, por lo que está disponible en invocaciones posteriores bash, por lo que esa es una forma de pasar la definición de la función a la bashinvocada por awk:

export -f d2h

Las únicas formas de awkejecutar un comando ( bashaquí) son con su system("cmd"), o print... | "cmd"o "cmd" | getline. En todos los casos, awkejecuta un shell para interpretar eso cmd, pero será sh, nobash . Por lo tanto, debe construir una línea de comando para sheso es una bashinvocación que interpreta una bashlínea de comando para invocar la función, por lo que debe 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("bash -c '\''d2h \"$1\"'\'' bash " shquote($2))}'

Eso significa ejecutar uno shy uno bashpara cada línea, por lo que será bastante ineficiente. Eso terminaría siendo incluso significativamente más ineficiente que tener bashque leer y dividir con while read loop:

(unset IFS; while read -r a b rest; do
  printf '%s\n' "$a"
  d2h "$b"
 done < file)
Stéphane Chazelas
fuente
0

Esto te 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 de la secuencia awk.

Mansur Ali
fuente
0

Solo un truco rápido demuestra @HaukeLaging command|getline :

1) deje que la entrada sea:

Dear friends
my name is `id -nu` and
today is `date "+%Y-%m-%d"`.

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.

2) Podemos expandir el comando de shell en línea mediante:

#!/usr/bin/gawk -f

BEGIN  { FS ="`";        }
NF==3  { $2 | getline $2 }
       { print           }

3) Uso (después del chmod habitual):

$ expand-inline input
Dear friends
my name is jjoao and
today is 2018-01-15.
JJoao
fuente