अगर स्टेटमेंट में grep कमांड के साथ एक स्ट्रिंग खोज कैसे करें?


11

मैं दो फाइलों में कई तार खोजना चाहता हूं। यदि दोनों फ़ाइलों में एक स्ट्रिंग मिलती है, तो कुछ बनाएं। यदि एक स्ट्रिंग केवल एक फ़ाइल में मिलती है, तो दूसरी चीज बनाएं।

मेरे आदेश अगले हैं:

####This is for the affirmative sentence in both files
if grep -qw "$users" "$file1" && grep -qw "$users" "$file2"; then

####This is for the affirmative sentence in only one file, and negative for the other one
if grep -qw "$users" "$file1" ! grep -qw "$users" "$file2"; then

क्या यह बयानों को नकारने और पुष्टि करने का एक सही तरीका है? pd मैं केएसएच शेल का उपयोग कर रहा हूं।

पहले ही, आपका बहुत धन्यवाद।

जवाबों:


11

इसे इस्तेमाल करे:

if grep -wq -- "$user" "$file1" && grep -wq -- "$user" "$file2" ; then
   echo "string avail in both files"
elif grep -wq -- "$user" "$file1" "$file2"; then
   echo "string avail in only one file"
fi
  • grep कई फ़ाइलों में पैटर्न खोज सकते हैं, इसलिए OR / NOT ऑपरेटर का उपयोग करने की कोई आवश्यकता नहीं है।

क्या प्रत्येक कमांड में "-wq" और "-qw" के बीच न्यूनतम अंतर है?
मारीस

2
नहीं, वे दोनों grep को -q और -w विकल्प प्रदान करते हैं।
ग्लेन जैकमैन

3
चर विस्तार पर कोई उद्धरण क्यों नहीं?
डी। बेन नोबल

@ D.BenKnoble यह सही ढंग से है: "$ उपयोगकर्ता" "$ file1"?
मेराज

1
@ मैरेयस हाँ जो सही है
डी। बेन नोबल

13

एक अन्य विकल्प:

grep -qw -- "$users" "$file1"; in_file1=$?
grep -qw -- "$users" "$file2"; in_file2=$?

case "${in_file1},${in_file2}" in
    0,0) echo found in both files ;;
    0,*) echo only in file1 ;;
    *,0) echo only in file2 ;;
      *) echo in neither file ;;
esac

अरे आप वैकल्पिक तरीके के लिए धन्यवाद। यह काफी अच्छी तरह से काम करता है !! मेरे पास एक और स्क्रिप्ट में पूरी तरह से काम करता है।
मेराज

बढ़िया विचार है! हमेशा सीखते रहना।
जो

7
n=0

#Or if you have more files to check, you can put your while here. 
grep -qw -- "$users" "$file1" && ((n++))
grep -qw -- "$users" "$file2" && ((n++))

case $n in 
   1) 
       echo "Only one file with the string"
    ;;
   2)
       echo "The two files are with the string"
   ;;
   0)
       echo "No one file with the string"
   ;;
   *)
       echo "Strange..."
   ;;
esac 

नोट: ((n++))एक ksh एक्सटेंशन (द्वारा समर्थित zshऔर bash) भी है। POSIX shसिंटैक्स में, आपको n=$((n + 1))इसके बजाय की आवश्यकता होगी ।


क्षमा करें, मैं ((n ++)) के बजाय $ ((n ++)) टाइप कर रहा था। भूल जाओ।
1981 में लुसियानो अंड्रेस मार्टिनी

1
ध्यान दें कि n=$((n++))कभी n के मूल्य बदल जाएगा क्योंकि n++है पद वेतन वृद्धि: यह रिटर्न वर्तमान मान n के लिए, तो वेतन वृद्धि n; फिर आपने चर को लौटाए गए मान पर सेट किया जो मूल n था।
ग्लेन जैकमैन

यदि आप मान सकते हैं कि आपके फ़ाइलनामों में newlines नहीं हैं local IFS=$'\n'; matches=( $(grep -lw "$users" "$file1" "$file2") ), और उपयोग करें case "${#matches[@]" in। @glenn: यह विचार आपके उत्तर पर लागू होता है, साथ ही, कई आक्रमणों से बचने के लिए भी grep। यह grep -l | wc -lभी काम करने के लिए पाइपिंग ।
पीटर कॉर्ड्स

@Peter जो एक अलग उत्तर IMO के रूप में लिखने लायक होगा।
स्टीफन किट

@StephenKitt: मैं नहीं जा रहा था क्योंकि मैं मनमाने ढंग से फ़ाइल नाम वर्णों को संभालने के लिए बुलेटप्रूफ तरीका नहीं खोज सका। लेकिन जब से आपको लगता है कि यह इसके लायक है, मैंने इसे वैसे भी लिखा था।
पीटर कॉर्ड्स

2

यदि आपके फ़ाइल नाम में नई लाइनें नहीं हैं, तो आप grepgrep से मेल खाने वाली फ़ाइलों के नाम प्रिंट करके, और परिणामों को गिनकर कई इनवॉइस से बच सकते हैं ।

 local IFS=$'\n'    # inside a function.  Otherwise use some other way to save/restore IFS
 matches=( $(grep -lw "$users" "$file1" "$file2") )

मैचों की संख्या है "${#matches[@]}"

यहां उपयोग करने का एक तरीका हो सकता grep --null -lwहै, लेकिन मुझे यकीन नहीं है कि आउटपुट को पार्स कैसे किया जाए । बैश के बजाय var=( array elements )एक \0सीमांकक का उपयोग करने का एक तरीका नहीं है \n। हो सकता है कि बैश का mapfileबेसिन ऐसा कर सकता है? लेकिन शायद नहीं, क्योंकि आप परिसीमन को निर्दिष्ट करते हैं -d string


आप कर सकते हैं count=$(grep -l | wc -l), लेकिन फिर आपके पास दो बाहरी प्रक्रियाएं हैं, इसलिए आप grepअलग-अलग दो फाइलों पर बस चला सकते हैं। (के बीच अंतर grepबनाम wcस्टार्टअप भूमि के ऊपर कांटा + कार्यकारी + डायनामिक लिंकर सामान की तुलना में बिल्कुल एक अलग प्रक्रिया शुरू करने छोटा है)।

इसके अलावा, wc -lआपको यह पता नहीं चलता है कि कौन सी फाइल मेल खाती है।


किसी सरणी में कैप्चर किए गए परिणामों के साथ, जो पहले से ही आप चाहते हैं, या यदि वास्तव में 1 मैच है, तो आप देख सकते हैं कि यह पहला इनपुट था या नहीं।

local IFS=$'\n'    # inside a function.  Otherwise use some other way to save/restore IFS
matches=( $(grep -lw "$users" "$file1" "$file2") )

# print the matching filenames
[[ -n $matches ]] && printf  'match in %s\n'  "${matches[@]}"

# figure out which input position the name came from, if there's exactly 1.
if [[ "${#matches[@]" -eq 1 ]]; then
    if [[ $matches == "$file1" ]];then
        echo "match in file1"
    else
        echo "match in file2"
    fi
fi

$matches${matches[0]}पहले सरणी तत्व के लिए आशुलिपि है ।


@StephenKitt: मेरा मतलब है -z, नहीं -0, उफ़। हाँ है कि मुद्रित करने के लिए फ़ाइल नाम के द्वारा अलग ग्रेप मिलेगा \0की तरह मैं पहले से ही इस सवाल का जवाब में बताया गया है, लेकिन तुम कैसे प्राप्त कर सकते हैं bash कि पार्स करने के लिए? आप सेट IFS=$'\0'या मूल रूप से find -print0स्टाइल आउटपुट के साथ सीधे बैश के साथ कुछ और सेट नहीं कर सकते ।
पीटर कॉर्ड्स

हां, मैंने बहुत तेजी से पढ़ा, उस अनुच्छेद को याद नहीं किया, और चीजों के बारे में नहीं सोचा (यही वजह है कि मैंने अपनी टिप्पणी हटा दी)। वहाँ एक रास्ता हो सकता है, लेकिन मैं अभी एक के बारे में नहीं सोच सकता, और जैसा कि आप कहते हैं कि यह समाधान को बहुत जटिल बनाने के लायक नहीं है जब किसी grepभी तरह से निपटने के लिए बस कुछ ही होते हैं ।
स्टीफन किट

1
mapfile -d $'\0'कार्यों की तरह है, लेकिन यह रिक्त स्थान के साथ newlines की जगह (मैं tweaking की कोशिश नहीं की है IFS)।
स्टीफन किट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.