Kabuk değişkenini a / pattern / awk olarak geçir


59

Aşağıdakiler benim kabuk fonksiyonlarımdan birinde:

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

Böylece olarak adlandırılan zaman _process $arg, $argolarak iletilir $1ve bir arama deseni olarak kullandı. Bu şekilde çalışır, çünkü kabuk $1awk deseni yerine genişler ! Ayrıca lawk programının içinde de bildirilerek kullanılabilir -v l="$line". Her şey yolunda.

Değişken olarak aramak için desen vermek aynı şekilde mümkün mü?

Aşağıdaki işe yaramayacak,

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

Çünkü awk /search/bir değişken olarak yorumlanmayacak , tam anlamıyla.

Yanıtlar:


46

Awk ~operatörünü kullanın ve sağ tarafta değişmez bir regex sağlamanız gerekmez:

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

Her ne kadar bu daha verimli olsa da (tüm dosyayı okumak zorunda değilsiniz)

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

Desene bağlı olarak, isteyebilirsiniz grep -Eq "$1"


Bu tam olarak istediğim şekilde çözen şey (1. örnek) çünkü hedefimi anlambilimimi koruyor. Teşekkürler.
branquito

1
BEGIN bloğunun kaldırıldığını not etmedim: atanmamış bir değişken, sayısal bağlamda veya boş dize olarak 0 olarak değerlendirilir. Yani, bir atanmamış değişken false olacakif (p) ...
Glenn Jackman

evet farkettim, her seferinde BEGIN bloğunda bir anahtar olarak kullanıldığından sıfıra ayarlanması gerekiyor. Ama ilginç bir şekilde şimdi komut dosyası kullanarak denedim $0 ~ patternve işe yaramadı, ama işe /'"$1"'/yarıyor !? : O
branquito

belki yolu $linealınırsa yapması gereken whois $line, $lineWHILE DO bloğundaki dosyadan gelen desen arama işlemidir.
branquito

Lütfen içeriğini göster $line- uygun biçimlendirme için bu soruyu yap.
glenn jackman

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

awkANSI C çıkış sırasını genişletme sorunu var ( \nnewline \fiçin, form beslemesi \\için, ters eğik çizgi için vb.) $1. Bu nedenle $1, düzenli ifadelerde yaygın olan ters eğik çizgi karakterleri içeriyorsa, bu bir sorun haline gelir (GNU awk4.2 veya üzeri, başlangıç @/ve bitiş değerleri /de sorun olur ). Bu sorundan muzdarip olmayan bir başka yaklaşım da yazmaktır:

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

Ne kadar kötü olacağı awkuygulamaya bağlı olacaktır .

$ 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

Hepsi awkgeçerli kaçış dizileri için aynı şekilde çalışır:

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

( $aolduğu gibi geçirilen içerik )

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

(olarak \\değiştirildi \ve \bbir geri alma karakteriyle değiştirildi).


Yani, örneğin \d{3}, üç basamak bulmak için bir model olsaydı, sizi iyi anladıysam, beklendiği gibi çalışmadığını mı söylüyorsunuz?
branquito

2
için \dhangi geçerli bir C kaçış sizin bağlıdır dizisi değil awkuygulanması (çalıştırmak awk -v 'a=\d{3}' 'BEGIN{print a}'kontrol etmek). Ancak \` or \ b , yes definitely. (BTW, I don't know of any awk implementations that understands \ d` için bir rakam anlamına gelir).
Stéphane Chazelas

diyor ki: awk uyarısı - kaçış dizisi \d' treated as plain d 'd {3}, sanırım bu durumda bir sorunum olur mu?
branquito

1
Üzgünüm, benim hatam, cevabımda bir yazım hatası vardı. Daha sonra ortam değişkeninin adı eşleşmesi gerektiğini ENVIRON["PATTERN"]için PATTERNortam değişkeni. Bir kabuk değişkeni kullanmak istiyorsanız, önce onu dışa aktarmanız ( export variable) ya da ENV=VALUE awk '...ENVIRON["ENV"]'cevabımdaki gibi env-var geçen sözdizimini kullanmanız gerekir .
Stéphane Chazelas

1
Çünkü ortamda bir komuta geçirilmesi için bir kabuk değişkenini vermeniz gerekir.
Stéphane Chazelas

5

Gibi bir şey deneyin:

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

Bu /regex/, kalıp bulma ile aynı şekilde davranırsa , bu iyi bir çözüm olabilir. Yapmaya çalışacağım.
branquito

1
Yaptığım hızlı testler aynı şekilde çalışıyor gibiydi, ama bunu garanti etmeye bile başlamayacağım ... :)
Hunter Eidson

0

Hayır, ancak deseni basitçe awk'ye ilettiğiniz çift tırnaklı dizgiye enterpolasyon yapabilirsiniz:

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

Şimdi, çift tırnaklı awk kelimesinden kaçmak zorunda olduğunuzu unutmayın, ancak yine de bunu başarmanın en basit yolu budur.


$patternBoşluklar içeriyorsa bu yol güvenli midir, yukarıdan gelen örneğim $ 1 "$ 1" çift tırnak işareti ile korunur, ancak sizin durumunuzda olanları gizlemeyin.
branquito

2
Orijinal örneğiniz, tek tırnaklı dizgiyi saniyede sonlandırır ', sonra $1çift ​​tırnak işaretlerini korur ve ardından awk programının ikinci yarısı için başka bir tek tırnaklı dizgiyi yapıştırır. Doğru anlarsam, bunun $1dıştaki tek tırnak işaretleri üzerinden korunma etkisi ile tam olarak aynı etkiye sahip olması gerekir - awk, etrafına koyduğunuz çift tırnak işaretlerini asla görmez.
Kilian Foth

4
Ama $patterniçeriyorsa ^/ {system("rm -rf /")};, başın büyük belada.
Stéphane Chazelas

Bu yaklaşımın yalnızca dezavantajı var mıdır?
branquito

-3

Bu örnekte, awk çalıştırılmadan önce ağlar değişkenini çözen eval işlevini kullanabilirsiniz.

nets="searchtext"
eval "awk '/"${nets}"/'" file.txt
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.