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
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
:
- 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.
- Nous pouvons étendre la commande shell en ligne par:
#!/usr/bin/gawk -f BEGIN { FS ="`"; } NF==3 { $2 | getline $2 } { print }
- 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 🙂
d2h
était un exécutable, mais pas si elle ‘ sa » fonction définie soit dans .bashrc ou dans le script shell « .source
) mais je peux ‘ f figure pourquoi cela ne fonctionne pas ‘ avec.bashrc
.$2
finit par être interprété comme du code shell.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") }'