Är det möjligt att använda bash-funktion inuti AWK på något sätt?
Exempelfil (sträng, int, int , int)
Mike 247808 247809 247810
Försöker konvertera värden från decimal till hexadecimal.
Funktion definierad antingen i .bashrc
eller i skalskript.
$ awk "{print $1 ; d2h($2)}" file awk: calling undefined function d2h input record number 1, file file source line number 1
Svar
Försök att använd system()
-funktion:
awk "{printf("%s ",$1); system("d2h " $2)}" file
I ditt fall system
ring d2h 247808
och lägg sedan till kommandos utdata till printf
output:
Mike 3C800
EDIT:
Eftersom system
använder sh
istället för bash
Jag kan inte hitta ett sätt att komma åt .bashrc
. Men du kan fortfarande använda funktioner från ditt nuvarande bash-skript:
#!/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:
Jag vet inte varför, men detta fungerar inte på min Ubuntu 16.04. Det här är konstigt eftersom det brukade fungera på Ubuntu 14.04.
Kommentarer
Svar
Du kan ringa bash från awk och använda dess utdata. Det är uppenbarligen farligt ur ett prestationsperspektiv om det händer för ofta. Citera man-sidan:
command | getline [var]
Kör kommandot som rör utgången antingen till $ 0 eller var,
-kommandot skulle vara ett bash-skript som innehåller funktionsdefinitionen och kör funktionen.
Svar
Konvertering från decimal till hexadecimal är något som awk
mycket väl kan göra själv. Och du kan definiera en awk
-funktion för att göra det:
function d2h(d) { return sprintf("%x", d) }
Nu för att svara på frågan i allmänhet, för att awk
ska köra bash
funktioner, du ”behöver awk
för att köra ett bash
skal, det bash
för att tolka definitionen av den funktionen och kalla den funktionen med värdet extraherat av awk
skickat som argument.
Inte trivialt.
bash
stöder exportfunktioner via miljön, så den är tillgänglig i efterföljande anrop av bash
, så att ”ett sätt att passera definitionen av funktionen till bash
åberopad av awk
:
export -f d2h
De enda sätten för awk
att utföra ett kommando (bash
h är) är med sin system("cmd")
, eller print... | "cmd"
eller "cmd" | getline
. I alla fall kör awk
ett skal för att tolka att cmd
, men det blir sh
, inte bash
. Så du måste konstruera en kommandorad för sh
som är en bash
anrop som tolkar en bash
kommandorad för att anropa funktionen, så du måste vara försiktig med att citera:
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))}"
Om du vill få utdata från funktionen tillbaka till awk
, du behöver överföra den via ett rör. För det använder du cmd | getline
istället för system(cmd)
(vilket lämnar cmd
” s stdout orörd).
cmd | getline line
lagrar en rad (strikt taget en post , poster är rader som standard), så för att få hela produktionen i de fall där den är gjord av flera rader, behöver du en slinga 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 att man kör en sh
och en bash
för varje anrop av funktionen , så kommer det att bli ganska ineffektivt. Det skulle bli ännu mer ineffektivt än att bash
läste och delade med en while read loop
:
(unset -v IFS; while read -r a b rest; do printf "%s\n" "$a" d2h "$b" done < file)
Observera också att sedan shellshock exporterar bash
nu funktioner i miljövariabler som heter BASH_FUNC_d2h%%
. Några sh
implementeringar inklusive mksh
och nyare versioner av dash
ta bort dessa miljövariabler från miljön:
$ 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å istället för att förlita dig på exportfunktionen för tunn funktion kan du skicka funktionsdefinitionen på något annat sätt. Det kan ske via en miljövariabel med ett vanligt namn:
BASH_FUNCTIONS=$(typeset -f d2h) awk " ... cmd = "exec bash -c "\""eval \"$BASH_FUNCTIONS\";" \ "d2h \"$1\""\"" bash " shquote($2) ..."
Svar
Prova att göra detta:
awk "{print $1 ; printf "%x\n", $2}" file
AFAIK, du kan inte använda en bash funktion i awk men bara ett skript. Du kan använda en awk-funktion om det behövs.
Svar
Använda en användardefinierad bash-funktion inuti awk
Ansvarsfriskrivning: Jag inser att detta inte är vad OP försöker göra, men Google kommer att leda andra som jag till detta svar.
Situation
Du har ett bash
-skript som är organiserat med funktioner (eftersom du inte hatar dig själv eller [de flesta] kollegor) och minst en av dessa funktioner behöver ring en annan inifrån 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
- jag representera Queens, hon växte upp i Brooklyn
Svar
Bara ett snabbt exempel för att visa @HaukeLaging ”s command|getline
:
- låt ingången vara:
Dear friends my name is `id -nu` and today is `date "+%Y-%m-%d"`.
där vi följer skal-syntax i ingången,
`command`
används för att beteckna inline-kommandon som ska ersättas med resultatet hans utförande.
- Vi kan utöka kommandot med inbyggt skal med:
#!/usr/bin/gawk -f BEGIN { FS ="`"; } NF==3 { $2 | getline $2 } { print }
- Användning (efter vanligt chmod):
$ expand-inline input Dear friends my name is jjoao and today is 2018-01-15.
Svar
Detta ger dig goda chanser.
cat ../logs/em2.log.1 |grep -i 192.168.21.15 |awk "{system("date"); print $1}"
systemfunktionen gör att du kan analysera bash-kommandot i awk stream.
Svar
Detta svar om för GNU awk, men andra versioner kan implementera samma trick. Tanken är att så länge den högra sidan av röret är exakt densamma och inte går ut, stänger awk inte röret. Men om det är annorlunda öppnar det ett nytt rör. Om du till exempel skriver:
awk "BEGIN{ shell= "/bin/bash" } { print $0 | "/bin/bash" } END { print "echo $a" | " /bin/bash" }"
kan du skriva:
a=5 echo $a
och få det förväntade (?) svaret 5: inget nytt skal skapades. Men i END-avsnittet skrev jag ett extra utrymme, så rörets RHS är annorlunda och ett nytt skal skapas utan värde för variabel a (och kommer därmed att skriva ut en tom rad vid utgången. Jag kan inte hitta den i dokumentation, men det rekommenderade sättet att använda långsiktiga rör är som jag har: placera kommandot i BEGIN-sektionen i en variabel och återanvänd den variabeln.
Ge en användardefinierad funktion till en bash-session och sedan återanvändning är en övning som lämnas åt läsaren 🙂
d2h
var en körbar, men inte om den ’ sa ” -funktionen definierad antingen i .bashrc eller i skalskript ”.source
) men jag kan ’ f figurera varför det inte fungerar ’ med.bashrc
.$2
slutar tolkas som skalkod.export -f d2h
fungerar inte ’, du kan göra det som för ksh / zsh: (\ 42 och \ 47 är flyktkoder för enkla och dubbla citat)CODE=$(typeset -f d2h) awk ' { system("bash -c \47eval \42$CODE\42; d2h \42"$2"\42\47") }'