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.