Przekaż zmienną powłoki jako / pattern / do awk


59

Posiadanie następujących w jednej z moich funkcji powłoki:

function _process () {
  awk -v l="$line" '
  BEGIN {p=0}
  /'"$1"'/ {p=1}
  END{ if(p) print l >> "outfile.txt" }
  '
}

, więc gdy zostanie wywołany jako _process $arg, $argzostanie przekazany jako $1i użyty jako wzorzec wyszukiwania. Działa to w ten sposób, ponieważ skorupa rozszerza się $1zamiast wzoru awk! Również lmoże być używany wewnątrz programu awk, zadeklarowane z -v l="$line". Wszystko w porządku.

Czy w ten sam sposób można podać wzorzec wyszukiwania jako zmienną?

Obserwowanie nie będzie działać,

awk -v l="$line" -v search="$pattern" '
  BEGIN {p=0}
  /search/ {p=1}
  END{ if(p) print l >> "outfile.txt" }
  '

, ponieważ awk nie będzie interpretowany /search/jako zmienna, ale dosłownie.

Odpowiedzi:


46

Użyj ~operatora awk i nie musisz podawać dosłownego wyrażenia regularnego po prawej stronie:

function _process () {
    awk -v l="$line" -v pattern="$1" '
        $0 ~ pattern {p=1} 
        END {if(p) print l >> "outfile.txt"}
    '  
}

Chociaż byłoby to bardziej wydajne (nie musisz czytać całego pliku)

function _process () {
    grep -q "$1" && echo "$line"
}

W zależności od wzoru, może chcesz grep -Eq "$1"


Właśnie to rozwiązuje w sposób, w jaki chciałem (pierwszy przykład), ponieważ zachowuje semantykę, co było moim celem. Dzięki.
branquito

1
Nie zauważyłem usunięcia bloku BEGIN: nieprzypisana zmienna jest traktowana jako 0 w kontekście numerycznym lub w przeciwnym razie pusty ciąg znaków. Tak więc nieprzypisaną zmienną będzie fałszywyif (p) ...
glenn jackman

tak, zauważyłem, że musi być ustawiony na bloku BEGIN na zero za każdym razem, ponieważ służy jako przełącznik. Ale co ciekawe, próbowałem teraz używać skryptów $0 ~ patterni to nie działa, jednak z /'"$1"'/tym działa !? : O
branquito

Może to ma coś wspólnego ze sposobem, $linesą pobierane, wyszukiwania wzorca odbywa się na wyjściu whois $line, $linepochodzące z pliku na jakiś czas blokują.
branquito

Pokaż treść $line- zrób to w swoim pytaniu, aby uzyskać prawidłowe formatowanie.
glenn jackman

17
awk  -v pattern="$1" '$0 ~ pattern'

Ma problem polegający na tym, że awkrozszerza sekwencje specjalne ANSI C (jak \ndla nowej linii, \fdla wysuwu formularza, \\dla odwrotnego ukośnika i tak dalej) w $1. Staje się więc problemem, jeśli $1zawiera znaki odwrotnego ukośnika, które są powszechne w wyrażeniach regularnych (w GNU awk4.2 lub nowszym problemem są również wartości zaczynające się @/i kończące na/ ). Innym podejściem, które nie cierpi z powodu tego problemu, jest napisanie go:

PATTERN=$1 awk '$0 ~ ENVIRON["PATTERN"]'

To, jak źle będzie, będzie zależeć od awkwdrożenia.

$ nawk -v 'a=\.' 'BEGIN {print a}'
.
$ mawk -v 'a=\.' 'BEGIN {print a}'
\.
$ gawk -v 'a=\.' 'BEGIN {print a}'
gawk: warning: escape sequence `\.' treated as plain `.'
.
$ gawk5.0.1 -v 'a=@/foo/' BEGIN {print a}'
foo

Wszystkie awkdziałają jednakowo dla prawidłowych sekwencji ucieczki:

$ a='\\-\b' awk 'BEGIN {print ENVIRON["a"]}' | od -tc
0000000   \   \   -   \   b  \n
0000006

(treść $aprzekazana w obecnej postaci)

$ awk -v a='\\-\b' 'BEGIN {print a}' | od -tc
0000000   \   -  \b  \n
0000004

( \\zmieniono na \i \bzmieniono na znak cofania).


Mówisz więc, że jeśli wzorem byłoby na przykład \d{3}znalezienie trzech cyfr, nie działałoby to zgodnie z oczekiwaniami, jeśli dobrze cię zrozumiałem?
branquito

2
dla \dktórych nie jest prawidłową sekwencją zmiany znaczenia C, która zależy od awkimplementacji (uruchom, awk -v 'a=\d{3}' 'BEGIN{print a}'aby sprawdzić). Ale dla \` or \ b , yes definitely. (BTW, I don't know of any awk implementations that understands \ d` jako cyfra).
Stéphane Chazelas

mówi: awk ostrzeżenie - sekwencja ucieczki \d' treated as plain d 'd {3}, więc myślę, że w tym przypadku miałbym problem?
branquito

1
Przepraszam, mój zły, miałem literówkę w swojej odpowiedzi. Nazwa wówczas zmiennej środowiskowej musi pasować ENVIRON["PATTERN"]do PATTERNzmiennej środowiskowej. Jeśli chcesz użyć zmiennej powłoki, musisz ją najpierw wyeksportować ( export variable) lub użyć ENV=VALUE awk '...ENVIRON["ENV"]'składni env-var, jak w mojej odpowiedzi.
Stéphane Chazelas

1
Ponieważ musisz wyeksportować zmienną powłoki, aby została przekazana w środowisku do polecenia.
Stéphane Chazelas

5

Wypróbuj coś takiego:

awk -v l="$line" -v search="$pattern" 'BEGIN {p=0}; { if ( match( $0, search )) {p=1}}; END{ if(p) print l >> "outfile.txt" }'

Jeśli zachowuje się tak samo jak /regex/w przypadku znalezienia wzorca, może to być dobre rozwiązanie. Spróbuję.
branquito

1
Szybkie testy, które przeprowadziłem, wydawały się działać tak samo, ale nawet nie zacznę tego gwarantować ... :)
Hunter Eidson

0

Nie, ale możesz po prostu interpolować wzorzec na ciąg znaków cudzysłowów przekazywanych do awk:

awk -v l="$line" "BEGIN {p=0}; /$pattern/ {p=1}; END{ if(p) print l >> \"outfile.txt\" }"

Zauważ, że teraz musisz uciec od podwójnie cytowanego literału awk, ale wciąż jest to najprostszy sposób na osiągnięcie tego.


Czy ten sposób jest bezpieczny, jeśli $patternzawiera spacje, mój przykład z góry będzie działał, ponieważ 1 USD jest chroniony podwójnymi cudzysłowami „1 USD”, ale nie wiem, co się stanie w twoim przypadku.
branquito

2
Twój oryginalny przykład kończy ciąg znaków pojedynczego cudzysłowu na sekundę ', a następnie chroni $1podwójne znaki cudzysłowu, a następnie przetwarza inny ciąg znaków pojedynczego cudzysłowu dla drugiej połowy programu awk. Jeśli dobrze rozumiem, powinno to mieć dokładnie taki sam efekt jak ochrona $1zewnętrznych pojedynczych cudzysłowów - awk nigdy nie widzi podwójnych cudzysłowów, które umieszczasz wokół niego.
Kilian Foth

4
Ale jeśli $patternzawiera ^/ {system("rm -rf /")};, to masz duże kłopoty.
Stéphane Chazelas

czy to tylko wada tego podejścia, gdy wszystkie są owinięte w „”?
branquito

-3

Możesz użyć funkcji eval, która rozwiązuje w tym przykładzie zmienną nets przed uruchomieniem awk.

nets="searchtext"
eval "awk '/"${nets}"/'" file.txt
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.