Is het mogelijk om de bash-functie op de een of andere manier binnen AWK te gebruiken?
Voorbeeldbestand (string, int, int , int)
Mike 247808 247809 247810
Probeert waarden om te zetten van decimaal naar hexadecimaal.
Functie gedefinieerd in .bashrc
of in shell-script.
$ awk "{print $1 ; d2h($2)}" file awk: calling undefined function d2h input record number 1, file file source line number 1
Antwoord
Probeer gebruik system()
functie:
awk "{printf("%s ",$1); system("d2h " $2)}" file
In jouw geval zal system
bel d2h 247808
en voeg de uitvoer van deze opdracht toe aan de printf
uitvoer:
Mike 3C800
BEWERK:
Omdat system
sh
gebruikt in plaats van bash
Ik kan “geen manier vinden om toegang te krijgen tot .bashrc
. Maar je kunt nog steeds functies van je huidige bash-script gebruiken:
#!/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:
Ik weet het niet waarom, maar dit werkt niet op mijn Ubuntu 16.04. Dit is vreemd, omdat het vroeger werkte op Ubuntu 14.04.
Reacties
Answer
Je kunt bash aanroepen vanuit awk en de uitvoer ervan gebruiken. Dat is natuurlijk gevaarlijk vanuit een prestatieperspectief als het te vaak gebeurt. Onder vermelding van de man-pagina:
command | getline [var]
Voer het commando uit om de uitvoer ofwel naar $ 0 of var te leiden,
commando zou een bash-script zijn dat de functiedefinitie bevat en de functie uitvoert.
Antwoord
Omzetten van decimaal naar hexadecimaal is iets dat awk
zelf heel goed kan. En je zou een awk
-functie kunnen definiëren om het te doen:
function d2h(d) { return sprintf("%x", d) }
Om de vraag nu in het algemene geval te beantwoorden: awk
wordt uitgevoerd bash
functies, je “d hebt awk
nodig om een bash
shell uit te voeren, die bash
om de definitie van die functie te interpreteren, en die functie aan te roepen, met de waarde geëxtraheerd door awk
doorgegeven als argumenten.
Niet triviaal.
bash
ondersteunt het exporteren van functies via de omgeving, dus het is beschikbaar in volgende aanroepen van bash
, dus dat is een manier om de definitie van de functie voor de bash
aangeroepen door awk
:
export -f d2h
De enige manieren waarop awk
een commando kan uitvoeren (bash
h ere) zijn met zijn system("cmd")
, of print... | "cmd"
of "cmd" | getline
. In alle gevallen voert awk
een shell uit om dat cmd
te interpreteren, maar het zal sh
, niet bash
. U moet dus een opdrachtregel maken voor sh
die een bash
aanroep is die een bash
opdrachtregel om de functie aan te roepen, dus je moet voorzichtig zijn met aanhalingstekens:
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))}"
Als je de uitvoer van de functie terug wilt krijgen in awk
, je “zou het terug moeten sturen via een pipe. Daarvoor zou je” cmd | getline
gebruiken in plaats van system(cmd)
(waardoor cmd
” s stdout onaangeroerd blijft).
cmd | getline line
slaat één regel op (strikt genomen één record , records zijn standaard regels), dus om de hele uitvoer te krijgen in de gevallen waarin het “uit meerdere regels bestaat,” heb je een lus nodig zoals:
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 ..."
Dat betekent dat er één sh
en één bash
moet worden uitgevoerd voor elke aanroep van de functie , dus het zal behoorlijk inefficiënt zijn. Dat zou uiteindelijk zelfs aanzienlijk inefficiënter zijn dan bash
het lezen en splitsen te laten doen met een while read loop
:
(unset -v IFS; while read -r a b rest; do printf "%s\n" "$a" d2h "$b" done < file)
Merk ook op dat sinds shellshock bash
nu functies exporteert in omgevingsvariabelen die de naam BASH_FUNC_d2h%%
. Sommige sh
implementaties, waaronder mksh
en nieuwere versies van dash
verwijderen die omgevingsvariabelen uit de omgeving:
$ 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
Dus in plaats van te vertrouwen op de flimsy functie export functie, zou je de functiedefinitie op een andere manier kunnen doorgeven. Het kan zijn via een omgevingsvariabele met een gebruikelijke naam:
BASH_FUNCTIONS=$(typeset -f d2h) awk " ... cmd = "exec bash -c "\""eval \"$BASH_FUNCTIONS\";" \ "d2h \"$1\""\"" bash " shquote($2) ..."
Answer
Probeer dit eens:
awk "{print $1 ; printf "%x\n", $2}" file
AFAIK, je kunt “geen bash gebruiken functie in awk maar alleen een script. U kunt indien nodig een awk-functie gebruiken.
Answer
Een door de gebruiker gedefinieerde bash-functie gebruiken inside awk
Disclaimer: Ik realiseer me dat dit niet is wat het OP probeert te doen, maar Google zal anderen zoals ik naar dit antwoord leiden.
Situatie
Je hebt een bash
script dat is georganiseerd met functies (omdat je jezelf of [de meeste] collegas niet haat) en ten minste 1 van die functies moet bel een ander vanuit awk
.
Oplossing
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
Uitvoer
$ ./example.sh 1. doin" it and 2. doin" it and 3. doin" it well
Reacties
- ik vertegenwoordigen Queens, ze groeide op in Brooklyn
Answer
Even een kort voorbeeld om @HaukeLaging “s te demonstreren command|getline
:
- laat invoer zijn:
Dear friends my name is `id -nu` and today is `date "+%Y-%m-%d"`.
waar we de shell-syntaxis volgen, wordt in de invoer
`command`
gebruikt om inline-opdrachten aan te duiden die moeten worden vervangen door het resultaat van zijn uitvoering.
- We kunnen het inline shell-commando uitbreiden met:
#!/usr/bin/gawk -f BEGIN { FS ="`"; } NF==3 { $2 | getline $2 } { print }
- Gebruik (na de gebruikelijke chmod):
$ expand-inline input Dear friends my name is jjoao and today is 2018-01-15.
Antwoord
Dit geeft je goede kansen.
cat ../logs/em2.log.1 |grep -i 192.168.21.15 |awk "{system("date"); print $1}"
Met de systeemfunctie kun je het bash-commando in een awk-stream parseren.
Antwoord
Dit antwoord is voor GNU awk, maar andere versies kunnen dezelfde truc implementeren. Het idee is dat zolang de rechterkant van de buis precies hetzelfde is en niet naar buiten komt, awk de buis niet sluit. Maar als het anders is, opent het een nieuwe pijp. Als u bijvoorbeeld typt:
awk "BEGIN{ shell= "/bin/bash" } { print $0 | "/bin/bash" } END { print "echo $a" | " /bin/bash" }"
, kunt u typen:
a=5 echo $a
en krijg het verwachte (?) antwoord 5: er is geen nieuwe shell uitgezet. Maar in de END-sectie typte ik een extra spatie, dus de RHS van de pijp is anders, en een nieuwe shell wordt voortgebracht zonder waarde voor variabele a (en zal dus een lege regel afdrukken bij het verlaten. Ik kan het niet vinden in de documentatie, maar de aanbevolen manier om pijpen voor de lange termijn te gebruiken is zoals ik heb gedaan: plaats het commando in de BEGIN-sectie in een variabele, en hergebruik die variabele.
Een door de gebruiker gedefinieerde functie geven aan een bash-sessie en dan is hergebruik een oefening die aan de lezer wordt overgelaten 🙂
d2h
waren een uitvoerbaar bestand, maar niet als het ‘ sa ” -functie gedefinieerd is in .bashrc of in shell-script “.source
) te gebruiken, maar ik kan ‘ figuur uit waarom het niet ‘ werkt met.bashrc
.$2
uiteindelijk wordt geïnterpreteerd als shellcode.export -f d2h
werkt niet ‘ t werk, je kunt het doen zoals voor ksh / zsh: (\ 42 en \ 47 zijn de escape-codes voor eenvoudige en dubbele aanhalingstekens)CODE=$(typeset -f d2h) awk ' { system("bash -c \47eval \42$CODE\42; d2h \42"$2"\42\47") }'