Er det mulig å bruke bash-funksjon inne i AWK på en eller annen måte?
Eksempelfil (streng, int, int , int)
Mike 247808 247809 247810
Prøver å konvertere verdier fra desimal til heksadesimal.
Funksjon definert enten i .bashrc
eller i skallskript.
$ awk "{print $1 ; d2h($2)}" file awk: calling undefined function d2h input record number 1, file file source line number 1
Svar
Prøv å bruk system()
-funksjon:
awk "{printf("%s ",$1); system("d2h " $2)}" file
I ditt tilfelle vil system
ring d2h 247808
og legg deretter utgangen av denne kommandoen til printf
output:
Mike 3C800
EDIT:
Som system
bruker sh
i stedet for bash
Jeg kan ikke finne en måte å få tilgang til .bashrc
. Men du kan fortsatt bruke funksjoner fra det nåværende bash-skriptet:
#!/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 vet ikke hvorfor, men dette fungerer ikke på min Ubuntu 16.04. Dette er rart, fordi det pleide å fungere på Ubuntu 14.04.
Kommentarer
Svar
Du kan ringe bash fra awk og bruke utdataene. Det er åpenbart farlig fra et ytelsesperspektiv hvis det skjer for ofte. Sitere mannssiden:
command | getline [var]
Kjør kommandorørutgangen enten til $ 0 eller var,
kommando ville være et bash-skript som inneholder funksjonsdefinisjonen og utfører funksjonen.
Svar
Konvertering fra desimal til heksadesimal er noe som awk
veldig godt kan gjøre selv. Og du kan definere en awk
funksjon for å gjøre det:
function d2h(d) { return sprintf("%x", d) }
Nå for å svare på spørsmålet generelt, for awk
for å kjøre bash
funksjoner, du «trenger awk
for å utføre et bash
skall, det bash
for å tolke definisjonen av den funksjonen, og kalle den funksjonen, med verdien ekstrahert av awk
gitt som argumenter.
Ikke trivielt.
bash
støtter eksportfunksjoner via miljøet, slik at det er tilgjengelig i påfølgende påkallelser av bash
, slik at det er en måte å passere definisjonen av funksjonen til bash
påkalt av awk
:
export -f d2h
De eneste måtene for awk
å utføre en kommando (bash
h ere) er med sin system("cmd")
, eller print... | "cmd"
eller "cmd" | getline
. I alle tilfeller kjører awk
et skall for å tolke at cmd
, men det vil være sh
, ikke bash
. Så du må lage en kommandolinje for sh
som er en bash
påkallelse som tolker en bash
kommandolinje for å påkalle funksjonen, så du må være forsiktig med å sitere:
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å utgangen av funksjonen tilbake til awk
, du trenger å overføre den tilbake via et rør. For det bruker du cmd | getline
i stedet for system(cmd)
(som lar cmd
» s stdout uberørt).
cmd | getline line
lagrer en linje (strengt tatt en post , postene er linjer som standard), så for å få hele produksjonen i tilfeller der den er laget av flere linjer, trenger du en sløyfe 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 betyr å kjøre en sh
og en bash
for hver hver påkallelse av funksjonen , så kommer til å være ganske ineffektivt. Det vil ende opp med å bli enda mer ineffektivt enn å ha bash
til å lese og dele med en while read loop
:
(unset -v IFS; while read -r a b rest; do printf "%s\n" "$a" d2h "$b" done < file)
Vær også oppmerksom på at siden shellshock eksporterer bash
nå funksjoner i miljøvariabler som heter BASH_FUNC_d2h%%
. Noen sh
implementeringer inkludert mksh
og nyere versjoner av dash
fjern disse miljøvariablene 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 å stole på eksportfunksjonen for spinkel funksjon, kan du passere funksjonsdefinisjonen på en annen måte. Det kan være via en miljøvariabel med et vanlig navn:
BASH_FUNCTIONS=$(typeset -f d2h) awk " ... cmd = "exec bash -c "\""eval \"$BASH_FUNCTIONS\";" \ "d2h \"$1\""\"" bash " shquote($2) ..."
Svar
Prøv å gjøre dette:
awk "{print $1 ; printf "%x\n", $2}" file
AFAIK, du kan ikke bruke en bash funksjon i awk, men bare et skript. Du kan bruke en awk-funksjon om nødvendig.
Svar
Ved å bruke en brukerdefinert bash-funksjon inside awk
Ansvarsfraskrivelse: Jeg skjønner at dette ikke er hva OP prøver å gjøre, men Google vil lede andre som meg til dette svaret.
Situasjon
Du har et bash
skript som er organisert med funksjoner (fordi du ikke hater deg selv eller [de fleste] kolleger) og minst én av disse funksjonene må ring en annen innenfra awk
.
Løsning
Skript
#!/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 representer Queens, hun ble oppvokst i Brooklyn
Svar
Bare et raskt eksempel for å demonstrere @HaukeLaging «s command|getline
:
- la input være:
Dear friends my name is `id -nu` and today is `date "+%Y-%m-%d"`.
der vi følger skallsyntaks, i inngangen, brukes
`command`
til å betegne innebygde kommandoer som skal erstattes av resultatet av hans henrettelse.
- Vi kan utvide inline shell-kommando med:
#!/usr/bin/gawk -f BEGIN { FS ="`"; } NF==3 { $2 | getline $2 } { print }
- Bruk (etter vanlig chmod):
$ expand-inline input Dear friends my name is jjoao and today is 2018-01-15.
Svar
Dette gir deg gode sjanser.
cat ../logs/em2.log.1 |grep -i 192.168.21.15 |awk "{system("date"); print $1}"
systemfunksjonen gjør at du kan analysere bash-kommandoen i awk stream.
Svar
Dette svaret hvis det gjelder GNU awk, men andre versjoner kan implementere det samme trikset. Tanken er at så lenge den høyre siden av røret er nøyaktig den samme og ikke kommer ut, lukker ikke awk røret. Men hvis det er annerledes, vil det åpne et nytt rør. Hvis du for eksempel 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å forventet (?) respons 5: ingen nye skall ble gytt. Men i SLUTT-seksjonen skrev jeg inn et ekstra mellomrom, slik at rørets RHS er annerledes, og et nytt skall er gytt uten verdi for variabel a (og vil dermed skrive ut en tom linje ved utgangen. Jeg finner den ikke i dokumentasjon, men den anbefalte måten å bruke langsiktige rør på er som jeg har: legg kommandoen i BEGIN-delen i en variabel, og bruk den variabelen på nytt.
Gi en brukerdefinert funksjon til en bash-økt og å gjenbruke det er en øvelse overlatt til leseren 🙂
d2h
var en kjørbar, men ikke hvis den ‘ sa » -funksjonen definerte enten i .bashrc eller i skallskript «.source
), men jeg kan ‘ f figur ut hvorfor det ikke fungerer ‘ med.bashrc
.$2
ender med å bli tolket som skallkode.export -f d2h
fungerer ikke ‘, du kan gjøre det som for ksh / zsh: (\ 42 og \ 47 er rømningskodene for enkle og doble anførselstegn)CODE=$(typeset -f d2h) awk ' { system("bash -c \47eval \42$CODE\42; d2h \42"$2"\42\47") }'