Korzystanie z funkcji powłoki bash w AWK

24

Czy w jakiś sposób można użyć funkcji bash w AWK?

Przykładowy plik (ciąg, int, int, int)

Mike 247808 247809 247810

Próba konwersji wartości z dziesiętnej na szesnastkową.

Funkcja zdefiniowana w .bashrc lub w skrypcie powłoki.

awk '{print $1 ; d2h($2)}' file

awk: wywołanie niezdefiniowanej funkcji d2h rekord wejściowy numer 1, numer pliku źródłowego pliku numer 1

malutki
źródło

Odpowiedzi:

27

Spróbuj użyć system()funkcji:

awk '{printf("%s ",$1); system("d2h " $2)}' file

W twoim przypadku systemzadzwoni, d2h 247808a następnie doda wyjście tego polecenia do printfwyjścia:

Mike 3C800

EDYTOWAĆ:

Jako systemzastosowania shzamiast bashnie mogę znaleźć sposobu na dostęp .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ż działało na Ubuntu 14.04.

akarilimano
źródło
Mogłoby to działać, gdyby d2hbyły wykonywalne, ale nie, jeśli jest to „funkcja zdefiniowana w .bashrc lub w skrypcie powłoki”.
Michael Homer
@MichaelHomer tak, masz rację. Dzięki twojemu komentarzowi zrozumiałem, że odpowiedziałem na pytanie, którego nikt nie zadał. Ale znalazłem sposób na użycie funkcji z bieżącego skryptu (i ewentualnie z innych skryptów za pośrednictwem source), ale nie mogę zrozumieć, dlaczego to nie działa .bashrc.
akarilimano
2
Jest to również podatność na wstrzykiwanie poleceń, ponieważ treść $2jest interpretowana jako kod powłoki.
Stéphane Chazelas
8

Możesz wywołać bash z awk i użyć jego danych wyjściowych. 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 potokując dane wyjściowe do $ 0 lub var,

polecenie byłoby skryptem bash, który zawiera definicję funkcji i wykonuje funkcję.

Hauke ​​Laging
źródło
Hauke ​​Laging, bardzo fajnie!
JJoao
Używałem tego wiele razy i działa dobrze.
Dave Rix
4

Spróbuj to zrobić:

awk '{print $1 ; printf "%x\n", $2}' file

AFAIK, nie możesz używać funkcji bash w awk, ale tylko skrypt. W razie potrzeby możesz użyć funkcji awk.

Gilles Quenot
źródło
3

Używanie zdefiniowanej przez użytkownika funkcji bash w awk

Oświadczenie: Zdaję sobie sprawę, że OP nie chce tego zrobić, ale Google poprowadzi innych, takich jak ja, do tej odpowiedzi.

Sytuacja

Masz bashskrypt zorganizowany z funkcjami (ponieważ nie nienawidzisz siebie ani [większości] współpracowników) i co najmniej jedna z tych funkcji musi wywołać inną od wewnątrz awk.

Rozwiązanie

Scenariusz

#!/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

Wydajność

$ ./example.sh
1. doin' it and
2. doin' it and
3. doin' it well
Bruno Bronosky
źródło
Reprezentuję Queens, wychowała się na Brooklynie
Bruno Bronosky
3

awkmoże uruchamiać awkfunkcje. Aby uruchomić bashfunkcje, musisz awkwykonać bashpowłokę, bashaby zinterpretować definicję tej funkcji i wywołać tę funkcję, z wartością wyodrębnioną przez awkprzekazane jako argumenty.

Nie trywialne.

bashobsługuje eksportowanie funkcji, więc jest dostępny w kolejnych wywołaniach bash, więc jest to jeden ze sposobów przekazania definicji funkcji do bashwywołanego przez awk:

export -f d2h

Jedynymi sposobami awkwykonania polecenia ( bashtutaj) są jego system("cmd")lub print... | "cmd"lub "cmd" | getline. We wszystkich przypadkach, awkuruchamia powłokę interpretowania że cmd, ale to będzie sh, nie bash. Musisz więc zbudować wiersz poleceń, shponieważ jest to bashwywołanie, które interpretuje bashwiersz polecenia w celu wywołania funkcji, więc musisz być ostrożny 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("bash -c '\''d2h \"$1\"'\'' bash " shquote($2))}'

To oznacza uruchomienie jednego shi jednego bashdla każdej linii, więc będzie dość nieefektywne. Byłoby to nawet znacznie bardziej nieefektywne niż bashczytanie i dzielenie za pomocą while read loop:

(unset IFS; while read -r a b rest; do
  printf '%s\n' "$a"
  d2h "$b"
 done < file)
Stéphane Chazelas
źródło
0

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 parsowanie komendy bash w strumieniu awk.

Mansur Ali
źródło
0

Szybki hack demonstruje @HaukeLaging command|getline :

1) niech wejście będzie:

Dear friends
my name is `id -nu` and
today is `date "+%Y-%m-%d"`.

Zgodnie ze składnią powłoki na wejściu

`command`

służy do oznaczania poleceń wbudowanych, które mają zostać zastąpione wynikiem jego wykonania.

2) Możemy rozszerzyć wbudowane polecenie powłoki o:

#!/usr/bin/gawk -f

BEGIN  { FS ="`";        }
NF==3  { $2 | getline $2 }
       { print           }

3) Zastosowanie (po zwykłym chmod):

$ expand-inline input
Dear friends
my name is jjoao and
today is 2018-01-15.
JJoao
źródło