Er det muligt at bruge bash-funktion inde i AWK på en eller anden måde?
Eksempelfil (streng, int, int , int)
Mike 247808 247809 247810
Forsøger at konvertere værdier fra decimal til hexadecimal.
Funktion defineret enten i .bashrc
eller i shell-script.
$ awk "{print $1 ; d2h($2)}" file awk: calling undefined function d2h input record number 1, file file source line number 1
Svar
Prøv at brug system()
-funktion:
awk "{printf("%s ",$1); system("d2h " $2)}" file
I dit tilfælde vil system
ring til d2h 247808
og tilføj derefter output fra denne kommando til printf
output:
Mike 3C800
EDIT:
Som system
bruger sh
i stedet for bash
Jeg kan ikke finde en måde at få adgang til .bashrc
. Men du kan stadig bruge funktioner fra dit nuværende bash-script:
#!/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:
Jeg ved det ikke hvorfor, men dette fungerer ikke på min Ubuntu 16.04. Dette er underligt, fordi det plejede at fungere på Ubuntu 14.04.
Kommentarer
Svar
Du kan ringe til bash fra awk og bruge dens output. Det er naturligvis farligt set fra et præstationsperspektiv, hvis det sker for ofte. Citering af mandsiden:
command | getline [var]
Kør kommando, der rør output ud i $ 0 eller var,
kommando ville være et bash-script, der indeholder funktionsdefinitionen og udfører funktionen.
Svar
Konvertering fra decimal til hexadecimal er noget, som awk
meget godt kan gøre selv. Og du kunne definere en awk
-funktion til at gøre det:
function d2h(d) { return sprintf("%x", d) }
Nu for at besvare spørgsmålet i almindelighed, skal awk
køre bash
funktioner, du “behøver awk
for at udføre en bash
shell, der bash
at fortolke definitionen af denne funktion og kalde den funktion med værdien ekstraheret af awk
videregivet som argumenter.
Ikke trivielt.
bash
understøtter eksportfunktioner via miljøet, så det er tilgængeligt i efterfølgende påkald af bash
, så det er en måde at passere definitionen af funktionen til bash
påkrævet af awk
:
export -f d2h
De eneste måder for awk
at udføre en kommando (bash
h ere) er med dens system("cmd")
eller print... | "cmd"
eller "cmd" | getline
. I alle tilfælde kører awk
en shell for at fortolke, at cmd
, men det vil være sh
, ikke bash
. Så du skal konstruere en kommandolinje til sh
som er en bash
påkaldelse, der fortolker en bash
kommandolinje for at påkalde funktionen, så du skal være forsigtig med at citere:
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))}"
Hvis du vil få output fra funktionen tilbage til awk
, skal du overføre det tilbage via et rør. Til det skal du bruge cmd | getline
i stedet for system(cmd)
(som efterlader cmd
” s stdout uberørt).
cmd | getline line
gemmer en linje (strengt taget en post , poster er som standard linjer), så for at få hele output i de tilfælde, hvor det er lavet af flere linjer, har du brug for en løkke som:
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 ..."
Det betyder at køre en sh
og en bash
for hver hver påkaldelse af funktionen , så vil være ret ineffektivt. Det ville ende med at blive endnu mere ineffektivt end at have bash
til at læse og opdele med en while read loop
:
(unset -v IFS; while read -r a b rest; do printf "%s\n" "$a" d2h "$b" done < file)
Bemærk også, at siden shellshock eksporterer bash
nu funktioner i miljøvariabler, der hedder BASH_FUNC_d2h%%
. Nogle sh
implementeringer inklusive mksh
og nyere versioner af dash
fjern disse miljøvariabler fra miljøet:
$ 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
Så i stedet for at stole på eksportfunktionen for spinkelfunktion, kan du passere funktionsdefinitionen på en anden måde. Det kunne ske via en miljøvariabel med et almindeligt navn:
BASH_FUNCTIONS=$(typeset -f d2h) awk " ... cmd = "exec bash -c "\""eval \"$BASH_FUNCTIONS\";" \ "d2h \"$1\""\"" bash " shquote($2) ..."
Svar
Prøv at gøre dette:
awk "{print $1 ; printf "%x\n", $2}" file
AFAIK, du kan ikke bruge en bash funktion i awk, men kun et script. Du kan bruge en awk-funktion, hvis det er nødvendigt.
Svar
Brug af en brugerdefineret bash-funktion inside awk
Ansvarsfraskrivelse: Jeg er klar over, at dette ikke er, hvad OP forsøger at gøre, men Google vil føre andre som mig til dette svar.
Situation
Du har et bash
script, der er organiseret med funktioner (fordi du ikke hader dig selv eller [de fleste] kolleger), og mindst 1 af disse funktioner skal ring til en anden indefra awk
.
Løsning
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
Output
$ ./example.sh 1. doin" it and 2. doin" it and 3. doin" it well
Kommentarer
- jeg repræsentere Queens, hun blev opvokset i Brooklyn
Svar
Bare et hurtigt eksempel for at demonstrere @HaukeLaging “s command|getline
:
- lad input være:
Dear friends my name is `id -nu` and today is `date "+%Y-%m-%d"`.
hvor vi følger shell-syntaks i input,
`command`
bruges til at betegne inline-kommandoer der skal erstattes af resultatet af hans henrettelse.
- Vi kan udvide inline shell-kommando med:
#!/usr/bin/gawk -f BEGIN { FS ="`"; } NF==3 { $2 | getline $2 } { print }
- Anvendelse (efter den sædvanlige chmod):
$ expand-inline input Dear friends my name is jjoao and today is 2018-01-15.
Svar
Dette giver dig gode chancer.
cat ../logs/em2.log.1 |grep -i 192.168.21.15 |awk "{system("date"); print $1}"
systemfunktion giver dig mulighed for at analysere bash-kommandoen inden for awk stream.
Svar
Dette svar, hvis det gælder GNU awk, men andre versioner kan implementere det samme trick. Tanken er, at så længe den højre side af røret er nøjagtig den samme og ikke kommer ud, lukker awk ikke røret. Men hvis det er anderledes, åbner det et nyt rør. Hvis du f.eks. Skriver:
awk "BEGIN{ shell= "/bin/bash" } { print $0 | "/bin/bash" } END { print "echo $a" | " /bin/bash" }"
kan du skrive:
a=5 echo $a
og få det forventede (?) svar 5: ingen ny skal blev skabt. Men i END-sektionen skrev jeg et ekstra mellemrum, så rørets RHS er anderledes, og en ny skal er skabt uden værdi for variabel a (og vil således udskrive en tom linje ved udgangen. Jeg kan ikke finde den i dokumentation, men den anbefalede måde at bruge langsigtede rør på er som jeg har: læg kommandoen i BEGIN-sektionen i en variabel, og genbrug den variabel.
At give en brugerdefineret funktion til en bash-session og derefter genbrug er det en øvelse, der er overladt til læseren 🙂
d2h
var en eksekverbar, men ikke hvis den ‘ sa ” funktion defineret enten i .bashrc eller i shell script “.source
), men jeg kan ‘ f figur ud hvorfor det ikke fungerer ‘ med.bashrc
.$2
ender med at blive fortolket som shell-kode.export -f d2h
fungerer ikke ‘, du kan gøre det som for ksh / zsh: (\ 42 og \ 47 er flugtkoder til enkle og dobbelte citater)CODE=$(typeset -f d2h) awk ' { system("bash -c \47eval \42$CODE\42; d2h \42"$2"\42\47") }'