Czy można w jakiś sposób użyć funkcji bash wewnątrz AWK?
Przykładowy plik (string, int, int , int)
Mike 247808 247809 247810
Próba konwersji wartości z dziesiętnych na szesnastkowe.
Funkcja zdefiniowana w .bashrc lub w skrypcie powłoki.
$ awk "{print $1 ; d2h($2)}" file awk: calling undefined function d2h input record number 1, file file source line number 1
Odpowiedź
Spróbuj użyj funkcji system():
awk "{printf("%s ",$1); system("d2h " $2)}" file
W Twoim przypadku system wywołaj d2h 247808, a następnie dołącz wyjście tego polecenia do printf wyjścia:
Mike 3C800
EDYTUJ:
Jako system używa sh zamiast bash Nie mogę „znaleźć sposobu, aby uzyskać dostęp do .bashrc. Ale nadal możesz używać funkcji z bieżącego skryptu bash:
#!/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
EDYCJA 2:
Nie wiem dlaczego, ale to nie działa na moim Ubuntu 16.04. To dziwne, ponieważ kiedyś działało na Ubuntu 14.04.
Komentarze
Odpowiedź
Możesz wywołać bash z awk i użyć jego wyjścia. Jest to oczywiście niebezpieczne z punktu widzenia wydajności, jeśli zdarza się to zbyt często. Cytując stronę podręcznika:
command | getline [var]
Uruchom polecenie, przesyłając dane wyjściowe do $ 0 lub var,
polecenie byłoby skryptem basha zawierającym definicję funkcji i wykonującym funkcję.
Odpowiedź
Konwersja z dziesiętnego na szesnastkowy to coś, co awk może zrobić samo. Możesz też zdefiniować funkcję awk , aby to zrobić:
function d2h(d) { return sprintf("%x", d) }
Teraz, aby odpowiedzieć na pytanie w ogólnym przypadku, aby awk uruchomić bash, potrzebowałbyś awk do wykonania powłoki bash, która bash aby zinterpretować definicję tej funkcji i wywołać tę funkcję z wartością wyodrębnioną przez awk przekazaną jako argumenty.
Nie jest to trywialne.
bash obsługuje eksportowanie funkcji przez środowisko, więc jest dostępny w kolejnych wywołaniach bash, więc jest to jeden sposób definicja funkcji w bash wywołana przez awk:
export -f d2h
Jedyne sposoby, w jakie awk może wykonać polecenie (bash h ere) są z system("cmd") lub print... | "cmd" lub "cmd" | getline. We wszystkich przypadkach awk uruchamia powłokę, aby zinterpretować to cmd, ale będzie to sh, a nie bash. Musisz więc utworzyć wiersz poleceń dla sh, czyli wywołania bash, które interpretuje bash wiersz poleceń, aby wywołać funkcję, więc musisz uważać z cytowaniem:
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))}"
Jeśli chcesz otrzymać wynik funkcji z powrotem do awk, „d musiałbyś przesłać go z powrotem potokiem. W tym celu” użyjesz cmd | getline zamiast system(cmd) (co pozostawia cmd” standardowe wyjście nietknięte).
cmd | getline line przechowuje jedną linię (ściśle mówiąc jeden rekord , rekordy są domyślnie wierszami), więc aby otrzymać cały wynik w przypadkach, gdy składa się on z kilku wierszy, potrzebujesz pętli takiej jak:
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 ..."
To oznacza uruchamianie jednego sh i jednego bash dla każdego wywołania funkcji , więc będzie dość nieefektywne. Byłoby to nawet znacznie bardziej nieefektywne niż bash wykonanie odczytu i podzielenia za pomocą while read loop:
(unset -v IFS; while read -r a b rest; do printf "%s\n" "$a" d2h "$b" done < file)
Należy również pamiętać, że od czasu shellshock bash eksportuje teraz funkcje w zmiennych środowiskowych o nazwach takich jak BASH_FUNC_d2h%%. Niektóre sh implementacje, w tym mksh i nowsze wersje dash usuń te zmienne środowiskowe ze środowiska:
$ 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
Więc zamiast polegać na kruchej funkcji eksportu funkcji, możesz przekazać definicję funkcji w inny sposób. Może to być za pośrednictwem zmiennej środowiskowej o zwykłej nazwie:
BASH_FUNCTIONS=$(typeset -f d2h) awk " ... cmd = "exec bash -c "\""eval \"$BASH_FUNCTIONS\";" \ "d2h \"$1\""\"" bash " shquote($2) ..."
Odpowiedź
Spróbuj to zrobić:
awk "{print $1 ; printf "%x\n", $2}" file
AFAIK, nie możesz używać basha funkcja awk, ale tylko skrypt. W razie potrzeby możesz użyć funkcji awk.
Odpowiedź
Używanie funkcji bash zdefiniowanej przez użytkownika inside awk
Zastrzeżenie: zdaję sobie sprawę, że nie to próbuje zrobić OP, ale Google poprowadzi innych takich jak ja do tej odpowiedzi.
Sytuacja
Masz skrypt bash, który zawiera funkcje (ponieważ nie nienawidzisz siebie ani [większości] współpracowników) i co najmniej jedna z tych funkcji musi zadzwoń do innego z poziomu awk.
Rozwiązanie
Skrypt
#!/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
Wyjście
$ ./example.sh 1. doin" it and 2. doin" it and 3. doin" it well
Komentarze
- I reprezentuje Queens, wychowała się na Brooklynie
Odpowiedź
Tylko krótki przykład, aby zademonstrować @HaukeLaging „s command|getline:
- niech dane wejściowe będą:
Dear friends my name is `id -nu` and today is `date "+%Y-%m-%d"`.
gdzie postępujemy według składni powłoki, na wejściu
`command`
jest używany do oznaczenia poleceń wbudowanych , które mają być zastąpione wynikiem jego wykonanie.
- Możemy rozszerzyć wewnętrzną komendę powłoki o:
#!/usr/bin/gawk -f BEGIN { FS ="`"; } NF==3 { $2 | getline $2 } { print }
- Użycie (po zwykłym chmod):
$ expand-inline input Dear friends my name is jjoao and today is 2018-01-15.
Odpowiedź
To da ci duże szanse.
cat ../logs/em2.log.1 |grep -i 192.168.21.15 |awk "{system("date"); print $1}"
Funkcja systemowa umożliwia analizowanie polecenia bash w strumieniu awk.
Odpowiedź
Ta odpowiedź dotyczy GNU awk, ale inne wersje mogą implementować tę samą sztuczkę. Chodzi o to, że dopóki prawa strona potoku jest dokładnie taka sama i nie wychodzi, awk nie zamyka potoku. Ale jeśli jest inny, otworzy nową rurę. Na przykład, jeśli wpiszesz:
awk "BEGIN{ shell= "/bin/bash" } { print $0 | "/bin/bash" } END { print "echo $a" | " /bin/bash" }"
, możesz wpisać:
a=5 echo $a
i uzyskać oczekiwaną (?) odpowiedź 5: nie pojawiła się nowa powłoka. Ale w sekcji END wpisałem dodatkową spację, więc RHS potoku jest inny, i pojawia się nowa powłoka bez wartości dla zmiennej a (i dlatego wypisze pustą linię przy wyjściu. Nie mogę jej znaleźć w ale zalecany sposób używania potoków długoterminowych jest taki, jak ja: umieść polecenie w sekcji BEGIN w zmiennej i ponownie użyj tej zmiennej.
Nadanie funkcji zdefiniowanej przez użytkownika sesji bash i ponowne użycie jest ćwiczeniem pozostawionym czytelnikowi 🙂
d2hbył plikiem wykonywalnym, ale nie, jeśli ' sa ” funkcja zdefiniowana w .bashrc lub w skrypcie powłoki „.source), ale mogę ' f figure wyjaśnij, dlaczego nie ' nie działa z.bashrc.$2jest w końcu interpretowana jako kod powłoki.export -f d2hnie ' t działa, możesz to zrobić tak jak dla ksh / zsh: (\ 42 i \ 47 to kody ucieczki dla prostych i podwójnych cudzysłowów)CODE=$(typeset -f d2h) awk ' { system("bash -c \47eval \42$CODE\42; d2h \42"$2"\42\47") }'