Utilisation de la fonction shell bash dans AWK

24

Est-il possible d'utiliser la fonction bash dans AWK d'une manière ou d'une autre?

Exemple de fichier (chaîne, int, int, int)

Mike 247808 247809 247810

Essayer de convertir des valeurs décimales en hexadécimales.

Fonction définie soit en .bashrc soit en script shell.

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

awk: appel de la fonction non définie d2h entrée numéro d'enregistrement 1, fichier fichier source ligne numéro 1

minuscule
la source

Réponses:

27

Essayez d'utiliser la system()fonction:

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

Dans votre cas system, appellera d2h 247808puis ajoutera la sortie de cette commande à la printfsortie:

Mike 3C800

MODIFIER:

En tant systemqu'utilisations shau lieu de, bashje ne trouve pas de moyen d'accéder .bashrc. Mais vous pouvez toujours utiliser les fonctions de votre script bash actuel:

#!/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

EDIT 2:

Je ne sais pas pourquoi, mais cela ne fonctionne pas sur mon Ubuntu 16.04. C'est étrange, car cela fonctionnait sur Ubuntu 14.04.

akarilimano
la source
Cela pourrait fonctionner s'il d2hs'agissait d'un exécutable, mais pas s'il s'agit d'une "fonction définie soit en .bashrc soit en script shell".
Michael Homer
@MichaelHomer oui, vous avez raison. Grâce à votre commentaire, j'ai réalisé que j'avais répondu à la question que personne n'avait posée. Mais j'ai trouvé un moyen d'utiliser les fonctions du script actuel (et éventuellement d'autres scripts via source) mais je ne peux pas comprendre pourquoi cela ne fonctionne pas .bashrc.
akarilimano
2
C'est également une vulnérabilité d'injection de commandes car le contenu de $2finit par être interprété comme du code shell.
Stéphane Chazelas
8

Vous pouvez appeler bash depuis awk et utiliser sa sortie. C'est évidemment dangereux du point de vue des performances si cela se produit trop souvent. Citant la page de manuel:

command | getline [var]

Exécutez la commande en redirigeant la sortie vers $ 0 ou var,

serait un script bash qui contient la définition de la fonction et exécute la fonction.

Hauke ​​Laging
la source
Hauke ​​Laging, très cool!
JJoao
Je l'ai utilisé plusieurs fois et cela fonctionne bien.
Dave Rix
4

Essayez de faire ceci:

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

AFAIK, vous ne pouvez pas utiliser une fonction bash dans awk mais seulement un script. Vous pouvez utiliser une fonction awk si nécessaire.

Gilles Quenot
la source
3

Utilisation d'une fonction bash définie par l'utilisateur dans awk

Avertissement: je me rends compte que ce n'est pas ce que le PO essaie de faire, mais Google mènera d'autres personnes comme moi à cette réponse.

Situation

Vous avez un bashscript qui est organisé avec des fonctions (parce que vous ne vous détestez pas ou [la plupart] des collègues) et au moins une de ces fonctions doit en appeler une autre de l'intérieur awk.

Solution

Scénario

#!/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

Sortie

$ ./example.sh
1. doin' it and
2. doin' it and
3. doin' it well
Bruno Bronosky
la source
Je représente le Queens, elle a grandi à Brooklyn
Bruno Bronosky
3

awkpeut exécuter des awkfonctions. Pour qu'il exécute des bashfonctions, vous devez awkexécuter un bashshell, celui bashd'interpréter la définition de cette fonction, et appeler cette fonction, avec la valeur extraite par awkpassé comme arguments.

Pas anodin.

bashprend en charge l'exportation de fonctions, il est donc disponible dans les invocations ultérieures de bash, c'est donc une façon de transmettre la définition de la fonction à l' bashappelé par awk:

export -f d2h

Les seules façons awkd'exécuter une commande ( bashici) sont avec son system("cmd"), ou print... | "cmd"ou "cmd" | getline. Dans tous les cas, awkexécute un shell pour interpréter cela cmd, mais ce ne sera shpas le cas bash. Vous devez donc construire une ligne de commande car shc'est une bashinvocation qui interprète une bashligne de commande pour appeler la fonction, vous devez donc être prudent en citant:

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))}'

Cela signifie en exécuter un shet un bashpour chaque ligne, donc ça va être assez inefficace. Cela finirait par être encore plus inefficace que de bashfaire la lecture et le fractionnement avec un while read loop:

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

Cela vous donnera de bonnes chances.

cat ../logs/em2.log.1 |grep -i 192.168.21.15 |awk '{system("date"); print $1}'

la fonction système vous permet d'analyser la commande bash dans un flux awk.

Mansur Ali
la source
0

Juste un petit hack démontre @HaukeLaging command|getline :

1) que l'entrée soit:

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

En suivant la syntaxe du shell, en entrée,

`command`

est utilisé pour désigner les commandes en ligne à remplacer par le résultat de son exécution.

2) Nous pouvons étendre la commande du shell en ligne en:

#!/usr/bin/gawk -f

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

3) Utilisation (après le chmod habituel):

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