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.