शेल चर को / पैटर्न / जागरण के रूप में पास करें


59

मेरे शेल कार्यों में निम्नलिखित में से एक:

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

, इसलिए जब बुलाया जाता है _process $arg, के रूप में $argपारित हो जाता है $1, और एक खोज पैटर्न के रूप में उपयोग किया जाता है। यह इस तरह से काम करता है, क्योंकि शेल $1जाग पैटर्न के स्थान पर फैलता है! इसके अलावा l, awk कार्यक्रम के अंदर इस्तेमाल किया जा सकता के साथ घोषित किया गया -v l="$line"। सब ठीक।

क्या एक चर के रूप में खोज करने के लिए पैटर्न देना उसी तरह संभव है?

निम्नलिखित काम नहीं करेगा,

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

, के रूप में awk /search/एक चर के रूप में व्याख्या नहीं करेगा , बल्कि शाब्दिक रूप से।

जवाबों:


46

Awk के ~संचालक का उपयोग करें , और आपको दाहिने हाथ की ओर शाब्दिक रेगेक्स प्रदान करने की आवश्यकता नहीं है:

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

हालांकि यह अधिक कुशल होगा (पूरी फाइल को पढ़ना नहीं होगा)

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

पैटर्न के आधार पर, हो सकता है grep -Eq "$1"


यह ठीक उसी तरह है जो मैं चाहता था (1 उदाहरण), क्योंकि यह शब्दार्थ रखता है, जो मेरा लक्ष्य था। धन्यवाद।
ब्रांकिटो

1
मैंने BEGIN ब्लॉक को हटाने पर ध्यान नहीं दिया: एक अप्रमाणित चर को सांख्यिक संदर्भ में 0 या अन्यथा रिक्त स्ट्रिंग के रूप में माना जाता है। तो, एक if (p) ...
अप्रकाशित

हां मैंने देखा, इसे हर बार शून्य करने के लिए BEGIN ब्लॉक पर सेट होने की आवश्यकता होती है, क्योंकि यह एक स्विच के रूप में कार्य करता है। लेकिन दिलचस्प रूप से मैंने अब स्क्रिप्ट का उपयोग करने की कोशिश की $0 ~ pattern, और यह काम नहीं करता है, हालांकि इसके साथ /'"$1"'/काम करता है !? : हे
शाखाय

शायद यह रास्ता के साथ कुछ है $lineलिया गया है, पैटर्न खोज के उत्पादन पर किया जाता है whois $line, $lineएक समय में एक फ़ाइल से आने वाले ब्लॉक करते हैं।
15

कृपया की सामग्री दिखाएं $line- उचित स्वरूपण के लिए इसे अपने प्रश्न में करें।
ग्लेन जैकमैन

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

इसमें एक मुद्दा है कि awkएएनएसआई सी एस्केप सीक्वेंस (जैसे \nन्यूलाइन के लिए, \fफॉर्म फीड के लिए, \\बैकस्लैश के लिए और इतने पर) में फैलता है $1। तो यह एक मुद्दा बन जाता है अगर $1इसमें बैकलैश कैरेक्टर होते हैं जो रेगुलर एक्सप्रेशंस (जीएनयू awk4.2 या इसके बाद के संस्करण के साथ शुरू होते हैं@// , जो वैल्यूज के साथ शुरू होते हैं और खत्म होते हैं ) भी एक समस्या है । एक अन्य दृष्टिकोण जो उस समस्या से ग्रस्त नहीं है, उसे लिखना है:

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

यह कितना बुरा होने वाला है, यह awkकार्यान्वयन पर निर्भर करेगा ।

$ 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

awkहालांकि सभी वैध भागने अनुक्रमों के लिए समान काम करते हैं:

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

(सामग्री के $aरूप में पारित)

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

( \\करने के लिए बदल \और \bएक बैकस्पेस चरित्र के लिए बदल)।


तो आप कह रहे हैं कि यदि पैटर्न \d{3}तीन अंकों को खोजने के लिए उदाहरण के लिए था , जो अपेक्षित रूप से काम नहीं करेगा, अगर मैं आपको अच्छी तरह से समझ गया हूं?
ब्रांकिटो

2
\dजिसके लिए एक मान्य सी एस्केप अनुक्रम नहीं है, जो आपके awkकार्यान्वयन ( awk -v 'a=\d{3}' 'BEGIN{print a}'जांच करने के लिए रन ) पर निर्भर करता है । लेकिन for \` or \ b , yes definitely. (BTW, I don't know of any awk implementations that understands \ d` का अर्थ एक अंक) है।
स्टीफन चेजलस

यह कहता है: awk चेतावनी - एस्केप अनुक्रम \d' treated as plain d 'd {3}, इसलिए मुझे लगता है कि मुझे इस मामले में कोई समस्या होगी?
ब्रान्क्विटो

1
क्षमा करें, मेरा बुरा, मेरे उत्तर में एक टाइपो था। तो वातावरण चर के नाम से मेल खाना चाहिए ENVIRON["PATTERN"]के लिए PATTERNवातावरण चर। यदि आप शेल चर का उपयोग करना चाहते हैं, तो आपको पहले इसे निर्यात करना होगा ( export variable) या ENV=VALUE awk '...ENVIRON["ENV"]'मेरे उत्तर के रूप में env-var पासिंग सिंटैक्स का उपयोग करना होगा ।
स्टीफन चेज़लस

1
क्योंकि आपको आदेश में पर्यावरण में पारित होने के लिए एक शेल चर निर्यात करने की आवश्यकता है।
स्टीफन चेज़लस

5

कुछ इस तरह की कोशिश करें:

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

यदि यह /regex/पैटर्न खोजने के संदर्भ में समान व्यवहार करता है , तो यह एक अच्छा समाधान हो सकता है। मै कोशिश करूँगा।
ब्रंकिटो

1
मेरे द्वारा चलाए गए त्वरित परीक्षण उसी तरह काम करते दिख रहे थे, लेकिन मैं इसकी गारंटी देना भी शुरू नहीं करूंगा ... :)
हंटर ईडनसन

0

नहीं, लेकिन आप पैटर्न को केवल उस डबल-उद्धृत स्ट्रिंग में प्रक्षेपित कर सकते हैं जिसे आप जागने के लिए पास करते हैं:

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

ध्यान दें कि अब आपको डबल-कोटेड ऑक शाब्दिक से बचना होगा, लेकिन यह अभी भी इसे पूरा करने का सबसे सरल तरीका है।


क्या इस तरह से सुरक्षित है यदि $patternरिक्त स्थान हैं, तो ऊपर से मेरा उदाहरण काम करेगा क्योंकि $ 1 "$ 1" दोहरे उद्धरण चिह्नों के साथ सुरक्षित है, हालांकि आपके मामले में ऐसा नहीं होता है।
चोकर

2
आपका मूल उदाहरण दूसरे पर एकल-उद्धृत स्ट्रिंग को समाप्त 'करता है, फिर $1डबल कोट्स के माध्यम से सुरक्षा करता है और फिर जाग कार्यक्रम के दूसरे छमाही के लिए एक और एकल-उद्धृत स्ट्रिंग को काटता है। अगर मैं सही ढंग से समझूं, तो $1बाहरी एकल उद्धरणों के माध्यम से रक्षा करने के समान ही इसका प्रभाव होना चाहिए - awk कभी भी दोहरे उद्धरणों को नहीं देखता है जो आप इसके चारों ओर देखते हैं।
किलियन फोथ

4
लेकिन अगर $patternइसमें शामिल है ^/ {system("rm -rf /")};, तो आप बड़ी मुसीबत में हैं।
स्टीफन चेज़लस

क्या इस दृष्टिकोण के उलट केवल "" में लिपटा हुआ है?
ब्रान्क्विटो

-3

आप eval फ़ंक्शन का उपयोग कर सकते हैं जो इस उदाहरण में हल करता है कि awk चलाने से पहले नेट चर है।

nets="searchtext"
eval "awk '/"${nets}"/'" file.txt
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.