Grep एक लाइन में दो शब्दों की खोज


46

मैं एक लाइन को फ़िल्टर करने का एक तरीका खोजने की कोशिश कर रहा हूं जिसमें "नींबू" और "चावल" शब्द है। मुझे पता है कि "नींबू" या "चावल" कैसे मिलेंगे लेकिन उनमें से दो नहीं। उन्हें दूसरे के बगल में होने की आवश्यकता नहीं है, केवल एक ही पंक्ति का पाठ।


1
किसी फ़ाइल के अंदर के सभी स्ट्रिंग्स को खोजने के लिए, आप फॉर लूप में grep चला सकते हैं: unix.stackexchange.com/a/462445/43233
Noam Manos

जवाबों:


62

"एक ही पंक्ति पर दोनों" का अर्थ है "'चावल' के बाद बेतरतीब अक्षर और उसके बाद 'नींबू' या दूसरा तरीका"।

रेगेक्स में जो है rice.*lemonया lemon.*rice। आप एक का उपयोग कर गठबंधन कर सकते हैं |:

grep -E 'rice.*lemon|lemon.*rice' some_file

यदि आप विस्तारित लोगों के बजाय सामान्य रेगेक्स का उपयोग करना चाहते हैं ( -Eतो आपको इससे पहले एक बैकस्लैश की आवश्यकता होगी |:

grep 'rice.*lemon\|lemon.*rice' some_file

अधिक शब्दों के लिए जो जल्दी से थोड़ा लंबा हो जाता है और आमतौर पर grepउदाहरण के लिए, कई कॉल का उपयोग करना आसान होता है :

grep rice some_file | grep lemon | grep chicken

आपका अंतिम पंक्ति है संयोजन के रूप नहीं अलगाव नहीं? बुद्धि के लिए: grep riceयुक्त लाइनों को पाता है rice। यह खिलाया जाता है grep lemonजिसमें केवल नींबू युक्त रेखाएँ मिलेंगी .. और इसी तरह। जबकि ओपी - और साथ ही आपके पूर्व जवाब - किसी भी [चावल | नींबू | चिकन] की अनुमति दे रहे हैं
javadba

स्क्रिप्ट संस्करण: askubuntu.com/a/879253/5696
जेफ

@ फ़्लोरियन डिस्च - दिमाग समझाता है कि इसमें |भाग जाने की आवश्यकता क्यों है grep? धन्यवाद!
भगोड़ा

1
@fugitive egrepविस्तारित रेगेक्स का उपयोग करता है जहां |OR तर्क के रूप में समझा जाता है। grepमूलभूत रेगेक्स के लिए चूक, जहां \|OR है
Sergiy Kolodyazhnyy

जैसा कि कहा गया है, grep'मैनपेज' egrepको हटा दिया गया है और इसे बदल दिया जाना चाहिए grep -E। मैंने तदनुसार उत्तर संपादित करने की स्वतंत्रता ली।
मिठाई

26

आप पहले grep कमांड के आउटपुट को दूसरे grep कमांड पर पाइप कर सकते हैं और यह दोनों पैटर्न से मेल खाएगा। तो, आप कुछ ऐसा कर सकते हैं:

grep <first_pattern> <file_name> | grep <second_pattern>

या,

cat <file_name> | grep <first_pattern> | grep <second_pattern>

उदाहरण:

आइए हमारी फ़ाइल में कुछ सामग्री जोड़ें:

$ echo "This line contains lemon." > test_grep.txt
$ echo "This line contains rice." >> test_grep.txt
$ echo "This line contains both lemon and rice." >> test_grep.txt
$ echo "This line doesn't contain any of them." >> test_grep.txt
$ echo "This line also contains both rice and lemon." >> test_grep.txt

फ़ाइल में क्या है:

$ cat test_grep.txt 
This line contains lemon.
This line contains rice.
This line contains both lemon and rice.
This line doesn't contain any of them.
This line also contains both rice and lemon.

अब, हम क्या चाहते हैं:

$ grep rice test_grep.txt | grep lemon
This line contains both lemon and rice.
This line also contains both rice and lemon.

हम केवल उन पंक्तियों को प्राप्त करते हैं जहां दोनों पैटर्न मेल खाते हैं। आप इसे विस्तारित कर सकते हैं और आउटपुट को दूसरे grep कमांड के लिए आगे "एंड" मैचों के लिए पाइप कर सकते हैं।


21

हालांकि सवाल 'grep' के लिए पूछता है, मैंने सोचा कि यह एक सरल 'awk' समाधान पोस्ट करने में मददगार हो सकता है:

awk '/lemon/ && /rice/'

यह आसानी से और अधिक शब्दों, या 'और' के अलावा अन्य बूलियन अभिव्यक्तियों के साथ बढ़ाया जा सकता है।


11

किसी भी क्रम में मैचों को खोजने के लिए एक और विचार का उपयोग कर रहा है:

grep के साथ -P (पर्ल-कम्पेटिबिलिटी) विकल्प और पॉजिटिव लुकहेड रेगेक्स(?=(regex)) :

grep -P '(?=.*?lemon)(?=.*?rice)' infile

या आप इसके बजाय नीचे उपयोग कर सकते हैं:

grep -P '(?=.*?rice)(?=.*?lemon)' infile
  • .*?कोई भी वर्ण मिलान साधन .घटनाओं शून्य है कि या अधिक बार *जब वे एक पैटर्न (के बाद वैकल्पिक हैं riceया lemon)। इसके ?पहले सब कुछ वैकल्पिक बनाता है (शून्य या हर चीज के मिलान का एक समय .*)

(?=pattern): पॉजिटिव लुकहैड: पॉजिटिव लुकहेड कंस्ट्रक्शन में कोष्ठकों की एक जोड़ी होती है, जिसमें ओपनिंग कोष्ठक के बाद एक प्रश्न चिह्न और एक बराबर चिन्ह होता है।

तो यह सभी पंक्तियों के साथ lemonऔर riceयादृच्छिक क्रम में दोनों को लौटाएगा । इसके अलावा यह |एस और डबल grepएस के उपयोग से बचना होगा ।


बाहरी लिंक: उन्नत ग्रीप विषय पॉजिटिव लुकहेड - डिजाइनरों के लिए जीआरपी



1

यदि हम स्वीकार करते हैं कि एक उत्तर प्रदान करना जो कि grepआधारित नहीं है, स्वीकार्य है, जैसे कि ऊपर दिए गए उत्तर के आधार पर awk, मैं एक सरल perlपंक्ति का प्रस्ताव करूंगा जैसे:

$ perl -ne 'print if /lemon/ and /rice/' my_text_file

खोज कुछ / सभी शब्दों के साथ मामले को अनदेखा कर सकती है /lemon/i and /rice/i। अधिकांश यूनिक्स / लिनक्स मशीनों पर पर्ल स्थापित होने के साथ-साथ वैसे भी जागृत होता है।


मना कर दिया!!! ;) क्योंकि यह कोई मतलब नहीं है .. :)
An0n

0

यहाँ grep पाइपिंग समाधान को स्वचालित करने के लिए एक स्क्रिप्ट है:

#!/bin/bash

# Use filename if provided as environment variable, or "foo" as default
filename=${filename-foo}

grepand () {
# disable word splitting and globbing
IFS=
set -f
if [[ -n $1 ]]
then
grep -i "$1" ${filename} | filename="" grepand "${@:2}"
else
# If there are no arguments, assume last command in pipe and print everything
cat
fi
}

grepand "$@"

1
इसे संभवतः कमांड स्ट्रिंग के निर्माण के बजाय एक पुनरावर्ती फ़ंक्शन का उपयोग करके कार्यान्वित किया जाना चाहिए eval, जो आसानी से टूट जाता है
muru

@muru एक संपादन का सुझाव देने के लिए स्वतंत्र महसूस करें। मैं टिप्पणी की सराहना करता हूं।
जेफ

1
इसे संपादित करते हुए ऐसा बहुत कुछ फिर से लिखना होगा, इसलिए मैं ऐसा नहीं करूंगा। यदि आप इसे जोड़ना चाहते हैं, तो यहां मैं कल्पना करता हूं कि यह कैसा दिखना चाहिए: paste.ubuntu.com/23915379
muru
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.