Utilisation de la fonction bash shell dans AWK

Est-il possible dutiliser la fonction bash dans AWK dune manière ou dune autre?

Exemple de fichier (string, int, int , int)

Mike 247808 247809 247810 

Tentative de conversion des valeurs décimales en hexadécimales.

Fonction définie soit dans .bashrc ou dans un script shell.

$ awk "{print $1 ; d2h($2)}" file awk: calling undefined function d2h input record number 1, file file source line number 1 

Réponse

Essayez de utilisez la fonction system():

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

Dans votre cas, system appelez d2h 247808, puis ajoutez la sortie de cette commande à printf sortie:

Mike 3C800 

MODIFIER:

Comme system utilise sh au lieu de bash Je ne peux « pas trouver un moyen daccé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. Cest étrange, car cela fonctionnait sous Ubuntu 14.04.

Commentaires

  • Cela pourrait fonctionner si d2h était un exécutable, mais pas si elle ‘ sa  » fonction définie soit dans .bashrc ou dans le script shell « .
  • @MichaelHomer oui, vous avez raison. Grâce à votre commentaire, jai réalisé que javais répondu à la question que personne navait posée. Mais jai trouvé un moyen dutiliser les fonctions du script actuel (et éventuellement dautres scripts via source) mais je peux ‘ f figure pourquoi cela ne fonctionne pas ‘ avec .bashrc.
  • Cela ‘ est également une vulnérabilité dinjection de commande car le contenu de $2 finit par être interprété comme du code shell.
  • Si export -f d2h doesn ‘ t fonctionne, vous pouvez le faire comme pour ksh / zsh: (\ 42 et \ 47 sont les codes déchappement pour les guillemets simples et doubles) CODE=$(typeset -f d2h) awk ' { system("bash -c \47eval \42$CODE\42; d2h \42"$2"\42\47") }'

Réponse

Vous pouvez appeler bash depuis awk et utiliser sa sortie. Cest é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,

La commande serait un script bash contenant la définition de la fonction et exécutant la fonction.

Réponse

La conversion de décimal en hexadécimal est quelque chose que awk peut très bien faire tout seul. Et vous pouvez définir une fonction awk pour le faire:

 function d2h(d) { return sprintf("%x", d) }  

Maintenant, pour répondre à la question dans le cas général, pour awk exécuter bash, vous « avez besoin de awk pour exécuter un bash shell, que bash pour interpréter la définition de cette fonction, et appeler cette fonction, avec la valeur extraite par awk passée en arguments.

Pas trivial.

bash prend en charge lexportation des fonctions via lenvironnement, il est donc disponible dans les invocations ultérieures de bash, de sorte que « est une façon de réussir la définition de la fonction au bash invoquée par awk:

export -f d2h 

Les seuls moyens pour awk dexécuter une commande (bash h ere) sont avec son system("cmd"), ou print... | "cmd" ou "cmd" | getline. Dans tous les cas, awk exécute un shell pour interpréter cela cmd, mais ce sera sh, pas bash. Vous devez donc créer une ligne de commande pour sh qui est un appel bash qui interprète un bash pour appeler la fonction, vous devez donc être prudent avec les guillemets:

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 vous souhaitez récupérer la sortie de la fonction dans awk, vous « auriez besoin de le transférer via un tube. Pour cela, vous » utiliseriez cmd | getline au lieu de system(cmd) (ce qui laisse la sortie stdout de cmd » intacte).

cmd | getline line stocke une ligne (à proprement parler un enregistrement , les enregistrements étant des lignes par défaut), donc pour obtenir la sortie entière dans les cas où elle « est composée de plusieurs lignes, vous avez » besoin dune boucle telle que:

 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 ..."  

Cela signifie exécuter un sh et un bash pour chaque appel de la fonction , donc va être assez inefficace. Cela finirait par être encore beaucoup plus inefficace que davoir bash faire la lecture et le fractionnement avec un while read loop:

(unset -v IFS; while read -r a b rest; do printf "%s\n" "$a" d2h "$b" done < file) 

Notez également que depuis shellshock, bash exporte désormais des fonctions dans des variables denvironnement nommées comme BASH_FUNC_d2h%%. Certaines sh implémentations, y compris mksh et les versions plus récentes de dash remove ces variables denvironnement de lenvironnement:

$ 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 

Donc, au lieu de vous fier à la fonction dexportation de fonction fragile, vous pouvez transmettre la définition de fonction dune autre manière. Cela peut se faire via une variable denvironnement avec un nom usuel:

 BASH_FUNCTIONS=$(typeset -f d2h) awk " ... cmd = "exec bash -c "\""eval \"$BASH_FUNCTIONS\";" \ "d2h \"$1\""\"" bash " shquote($2) ..."  

Réponse

Essayez de faire ceci:

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

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

Réponse

Utilisation dune fonction bash définie par lutilisateur inside awk

Clause de non-responsabilité: Je me rends compte que ce nest pas ce que lOP essaie de faire, mais Google en mènera dautres comme moi vers cette réponse.

Situation

Vous avez un script bash 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 un autre depuis awk.

Solution

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 

Sortie

$ ./example.sh 1. doin" it and 2. doin" it and 3. doin" it well 

Commentaires

  • je représente Queens, elle a été élevée à Brooklyn

Réponse

Juste un exemple rapide pour démontrer @HaukeLaging « s command|getline:

  1. Soit lentrée:
Dear friends my name is `id -nu` and today is `date "+%Y-%m-%d"`. 

où nous suivons la syntaxe du shell, dans lentrée,

`command` 

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

  1. Nous pouvons étendre la commande shell en ligne par:
#!/usr/bin/gawk -f BEGIN { FS ="`"; } NF==3 { $2 | getline $2 } { print } 
  1. Utilisation (après le chmod habituel):
$ expand-inline input Dear friends my name is jjoao and today is 2018-01-15. 

Réponse

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 danalyser la commande bash dans le flux awk.

Réponse

Cette réponse est pour GNU awk, mais dautres versions peuvent implémenter la même astuce. Lidée est que tant que le côté droit du tuyau est exactement le même et ne sort pas, awk ne ferme pas le tuyau. Mais si cest différent, cela ouvrira un nouveau tuyau. Par exemple, si vous tapez:

awk "BEGIN{ shell= "/bin/bash" } { print $0 | "/bin/bash" } END { print "echo $a" | " /bin/bash" }" 

, vous pouvez taper:

a=5 echo $a 

et obtenir la réponse attendue (?) 5: aucun nouveau shell na été généré. Mais dans la section END, jai tapé un espace supplémentaire, donc le RHS du tube est différent, et un nouveau shell est généré sans valeur pour la variable a (et affichera donc une ligne vide à la sortie. Je ne le trouve pas dans le documentation, mais la manière recommandée dutiliser des tubes à long terme est comme je lai fait: mettez la commande dans la section BEGIN dans une variable, et réutilisez cette variable.

Donner une fonction définie par lutilisateur à une session bash et puis le réutiliser est un exercice laissé au lecteur 🙂

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *