"Xargs grep" क्या करता है?


25

मुझे grepकमांड पता है और मैं इसकी कार्यक्षमता के बारे में सीख रहा हूं xargs, इसलिए मैं इस पेज के माध्यम से पढ़ता हूं जो xargsकमांड का उपयोग करने के तरीके के बारे में कुछ उदाहरण देता है ।

मैं अंतिम उदाहरण से भ्रमित हूं, उदाहरण 10. यह कहता है "xargs कमांड सभी फाइलों को खोजने के लिए grep कमांड को निष्पादित करता है (फाइंड कमांड द्वारा प्रदान की गई फ़ाइलों के बीच) जिसमें एक स्ट्रिंग 'stdlib.h' शामिल था"

$ find . -name '*.c' | xargs grep 'stdlib.h'
./tgsthreads.c:#include
./valgrind.c:#include
./direntry.c:#include
./xvirus.c:#include
./temp.c:#include
...
...
...

हालांकि, बस उपयोग करने के लिए क्या अंतर है

$ find . -name '*.c' | grep 'stdlib.h'

?

जाहिर है, मैं अभी भी संघर्ष कर रहा हूं कि वास्तव में xargs क्या कर रहा है, इसलिए किसी भी मदद की सराहना की जाती है!


2
यह प्रश्न सहायक हो सकता है: XArgs की आवश्यकता कब होती है?
TheOdd

जवाबों:


30
$ find . -name '*.c' | grep 'stdlib.h'

यह आउटपुट (stdout) * से find(stdin of) * grep 'stdlib.h' टेक्स्ट के रूप में (यानी फ़ाइलनाम को टेक्स्ट के रूप में माना जाता है) को पाइप करता है । grepअपनी सामान्य बात करता है और इस पाठ में मेल खाने वाली लाइनें (कोई भी फ़ाइल नाम जिसमें स्वयं पैटर्न होता है) पाता है। फ़ाइलों की सामग्री को कभी नहीं पढ़ा जाता है।

$ find . -name '*.c' | xargs grep 'stdlib.h'

यह एक कमांड grep 'stdlib.h' का निर्माण करता है, जिसमें से प्रत्येक परिणाम findएक तर्क है - इसलिए यह प्रत्येक फ़ाइल के अंदर मैच के लिए दिखेगा find( द्वारा xargsदिए गए आदेशों में इसके स्टड को तर्कों में बदलने के रूप में सोचा जा सकता है) *

-type fअपनी खोज कमांड में उपयोग करें , या आपको grepनिर्देशिकाओं के मिलान के लिए त्रुटियां मिलेंगी । इसके अलावा, अगर फ़ाइलनाम में जगह है, xargsतो बुरी तरह से खराब हो जाएगा, इसलिए जोड़कर -print0और xargs -0अधिक विश्वसनीय परिणामों के लिए अशक्त विभाजक का उपयोग करें :

find . -type f -name '*.c' -print0 | xargs -0 grep 'stdlib.h'

* इन अतिरिक्त व्याख्यात्मक बिंदुओं को @cat द्वारा टिप्पणी में सुझाए गए अनुसार जोड़ा


2
आप ध्यान देने योग्य बात पर विचार हो सकता (क्योंकि ऐसा लगता है आप छोड़े गए) प्रमुख मुद्दा है कि |पाइप stdout ग्रेप के लिए stdin जो ग्रेप के तर्कों के समान नहीं है और भ्रमित परिणाम देता है।
बिल्ली

1
या GNU फाइंड का उपयोग करें find -name '*.c' -exec grep stdlib.h {} +। मैं बहुत अधिक वास्तव में xargs का उपयोग कभी नहीं करता। यह भी आश्चर्यचकित है कि किसी ने भी उल्लेख नहीं किया है कि xargs grep $(find)प्रतिस्थापन के लिए एक समान उद्देश्य प्रदान करता है , इसलिए मैंने अपने स्वयं के उत्तर लिखा। कम सीमाओं और समस्याओं के साथ आदेश प्रतिस्थापन के रूप में xargs की व्याख्या करना स्वाभाविक लगता है।
पीटर कॉर्डेस

एक स्थिति जिस पर मैं xargs का उपयोग करता हूं, यदि मैं खोज के परिणामस्वरूप बहुत सारी फाइलें हटा रहा हूं। यदि आप सिर्फ -exec rm करते हैं, तो यह एक बार में प्रत्येक फ़ाइल पर rm चलाएगा, जो बहुत ही अक्षम है। Xargs को पाइपिंग उन सभी को एक बार में एक rm के साथ करेगा। कहना -50 (एक समय में 50 करो) के साथ सीमित करने से कमांड लाइन अतिप्रवाह (बहुत सारी फ़ाइलों के साथ समस्या) को रोका जा सकता है।
lsd

1
@lsd: find -deleteउस विशेष मामले के लिए क्यों नहीं ? या इसके अलावा अन्य आदेशों के लिए rm, यदि आपको GNU मिल जाता है, तो -exec some_command {} +समूहों में समूह जैसे xargs, इसके बजाय \;कमांड को चलाने का व्यवहार प्रत्येक के लिए अलग होता है।
पीटर कॉर्डेस

@lsd findप्रत्येक फ़ाइल पर कमांड चलाता है यदि और केवल यदि यह -exec command \;दोनों का उपयोग कर रहा है xargsऔर -exec command \+सिस्टम द्वारा अनुमति दी गई अधिकतम तर्कों के साथ कमांड को कॉल करेगा। दूसरे शब्दों में, वे समतुल्य हैं
सर्गी कोलोडियाज़नी

6

xargs इसका मानक इनपुट लेता है और इसे कमांड लाइन आर्ग्स में बदल देता है।

find . -name '*.c' | xargs grep 'stdlib.h' के समान है

grep 'stdlib.h' $(find . -name '*.c')  # UNSAFE, DON'T USE

और एक ही आदेश पंक्ति के लिए फ़ाइल नाम की सूची के रूप में लंबे समय के रूप में लंबे समय के रूप में एक ही परिणाम दे देंगे। (लिनक्स एकल कमांड लाइन पर मेगाबाइट टेक्स्ट का समर्थन करता है, इसलिए आमतौर पर आपको xargs की आवश्यकता नहीं होती है।)


लेकिन ये दोनों ही चूसते हैं, क्योंकि वे टूटते हैं यदि आपके फ़ाइलनाम में रिक्त स्थान होते हैं । इसके बजाय, find -print0 | xargs -0काम करता है, लेकिन ऐसा करता है

find . -name '*.c' -exec grep 'stdlib.h' {} +

यह कभी भी फ़ाइल नाम को कहीं भी पाइप नहीं करता है: findउन्हें एक बड़ी कमांड लाइन में बैच देता है और grepसीधे चलता है।

\;+प्रत्येक फ़ाइल के लिए अलग से रन grep के बजाय , जो बहुत धीमा है। ऐसा मत करो। लेकिन +यह एक GNU एक्सटेंशन है, इसलिए xargsयदि आप GNU ढूंढ नहीं पाते हैं , तो आपको इसे कुशलतापूर्वक करने की आवश्यकता है।


यदि आप बाहर निकलते हैं xargs, find | grepतो इसका पैटर्न findप्रिंट करने वाले फ़ाइलनामों की सूची से मेल खाता है ।

तो उस बिंदु पर, आप बस कर सकते हैं find -name stdlib.h। बेशक, साथ में -name '*.c' -name stdlib.h, आपको कोई आउटपुट नहीं मिलेगा क्योंकि वे पैटर्न दोनों से मेल नहीं खा सकते हैं, और खोज का डिफ़ॉल्ट व्यवहार नियमों को एक साथ करना है।

स्थानापन्न lessकी प्रक्रिया में किसी भी बिंदु पर देखने के लिए क्या उत्पादन पाइप लाइन के किसी भी हिस्से पैदा करता है।


आगे पढें: http://mywiki.wooledge.org/BashFAQ में कुछ बेहतरीन चीजें हैं।


1
GNU xargs -dको विभाजक भी सेट करना होता है, इसलिए आप -d'\n'एक नई-लाइन-से-अलग सूची को संभालने के लिए उपयोग कर सकते हैं , जो तब उपयोगी हो सकती है जब आप किसी फ़ाइल में फ़ाइल नामों की सूची को संभालते हैं, आदि (जब तक फ़ाइल नाम नहीं होता है उन में newlines, वह है।)
ilkachachu

@ilkachachu: हाँ, फ़ाइल नाम में नए स्थान रिक्त स्थान की तुलना में बहुत अधिक दुर्लभ हैं, क्योंकि वे अधिकांश स्क्रिप्ट को तोड़ते हैं। myfunc(){ local IFS=$'\n'; fgrep stdlib.h` $ (खोज) ; }भी इसी प्रभाव के साथ काम करता है। या वन-लाइनर के रूप में, एक सब- (IFS=...; cmd...)आईईएस को बचाने / बहाल करने के बिना IFS में परिवर्तन को समाहित करने का काम भी करता है।
पीटर कॉर्ड्स

@PeterCordes कृपया command $( find )सामान का प्रकार न करें । रिक्त स्थान और विशेष पात्रों के साथ समस्याग्रस्त फाइलनाम इस प्रकार की चीज़ को तोड़ सकते हैं। बहुत कम से कम डबल उद्धरण कमांड प्रतिस्थापन।
सर्गी कोलोडियाज़नी

@SergiyKolodyazhnyy: यह इंगित करने के लिए धन्यवाद कि ऐसा लगता है कि मैं वास्तव में ऐसा करने की सिफारिश कर रहा हूं। स्किमिंग करने वाले लोग अगले भाग को पढ़ने के बजाय कॉपी / पेस्ट कर सकते हैं। उस पते को अपडेट किया गया।
पीटर कॉर्ड्स

@SergiyKolodyazhnyy: या आप मेरी टिप्पणी का जवाब दे रहे थे? ध्यान दें कि मैंने सेट किया है IFSइसलिए यह उपयोग करने के बराबर है xargs '-d\n'। ग्लोब विस्तार और शेल मेटाचैकर प्रसंस्करण कमांड प्रतिस्थापन के प्रभाव से पहले होता है, इसलिए मुझे लगता है कि इसमें फ़ाइल नाम के साथ भी सुरक्षित है $()या >। सहमत हैं कि कमांड प्रतिस्थापन पर शब्द-विभाजन का उपयोग करना एकतरफा इंटरएक्टिव उपयोग के अलावा अच्छा नहीं है, जहां आप फ़ाइल नाम के बारे में कुछ जानते हैं। लेकिन command "$(find)"केवल तभी उपयोगी है जब आप उम्मीद करते हैं कि यह ठीक 1 फ़ाइल नाम का उत्पादन करे ...
पीटर कॉर्डेस

5

सामान्य तौर पर, उन xargsमामलों के लिए उपयोग किया जाता है जहां आप पाइप (प्रतीक के साथ) करेंगे| ) एक कमांड से दूसरे कमांड में कुछ ( Command1 | Command2), लेकिन पहले कमांड से आउटपुट दूसरी कमांड के इनपुट के रूप में सही ढंग से प्राप्त नहीं होता है।

यह आम तौर पर तब होता है जब दूसरी कमांड स्टैण्डर्ड इनपुट को स्टैण्डर्ड इन (स्टडिन) के माध्यम से सही ढंग से हैंडल नहीं करती है (जैसे: इनपुट के रूप में कई लाइन्स, जिस तरह से लाईनें होती हैं, इनपुट के रूप में उपयोग किए जाने वाले कैरेक्टर, इनपुट के रूप में कई पैरामीटर्स, डेटा टाइप के रूप में प्राप्त होता है। इनपुट, आदि ..)। आपको एक त्वरित उदाहरण देने के लिए, निम्नलिखित का परीक्षण करें:

उदाहरण 1:

ls | echo- यह कुछ भी नहीं करेगा क्योंकि echoवह नहीं जानता कि उसे प्राप्त इनपुट को कैसे संभालना है। अब इस मामले में यदि हम इसका उपयोग xargsकरते हैं तो इनपुट को इस तरह से संसाधित करेगा कि इसे सही तरीके से संभाला जा सके echo(जैसे: सूचना की एक पंक्ति के रूप में)

ls | xargs echo- यह lsएक लाइन में से सभी जानकारी आउटपुट करेगा

उदाहरण 2:

मान लीजिए कि मेरे पास एक फ़ोल्डर के अंदर कई goLang फाइलें हैं जिन्हें गो कहा जाता है। मैं उनके साथ कुछ इस तरह की तलाश करूंगा:

find go -name *.go -type f | echo- लेकिन अगर पाइप वहां और echoअंत में प्रतीक है , तो यह काम नहीं करेगा।

find go -name *.go -type f | xargs echo- यहाँ यह धन्यवाद के लिए काम करेगा, xargsलेकिन अगर मैं findएक पंक्ति में कमांड से प्रत्येक प्रतिक्रिया चाहता था, तो मैं निम्नलिखित कार्य करूंगा:

find go -name *.go -type f | xargs -0 echo- इस मामले में, उसी आउटपुट से findदिखाया जाएगा echo

इस तरह के cp, echo, rm, lessऔर अन्य लोगों को इनपुट के साथ बेहतर तरीके से काम करने की आवश्यकता होती है, जिनका उपयोग करने पर लाभ मिलता है xargs


4

xargs फ़ाइलों की सूची पर आधारित (आमतौर पर) कमांड लाइन तर्क को ऑटो उत्पन्न करने के लिए उपयोग किया जाता है।

इसलिए फॉलोइंग xargsकमांड का उपयोग करने के लिए कुछ विकल्पों पर विचार करना :

find . -name '*.c' -print0 | xargs -0 grep 'stdlib.h'

मूल रूप से अन्य उत्तरों में वर्णित नहीं किए गए अन्य विकल्पों के बजाय इसका उपयोग करने के कई कारण हैं:

  1. find . -name '*.c' -exec grep 'stdlib.h' {}\; एक उत्पन्न करेगा grepहर फ़ाइल के लिए प्रक्रिया - यह आमतौर पर बुरा अभ्यास माना जाता है, और कई फाइलें पाए जाने पर सिस्टम पर एक बड़ा भार डाल सकता है।
  2. यदि बहुत सारी फाइलें हैं, तो एक grep 'stdlib.h' $(find . -name '*.c')कमांड की संभावना विफल हो जाएगी, क्योंकि $(...)ऑपरेशन का आउटपुट शेल की अधिकतम कमांड लाइन की लंबाई से अधिक होगा

जैसा कि अन्य उत्तरों में उल्लेख किया गया है, इस परिदृश्य में तर्क और xargs के -print0तर्क का उपयोग करने का कारण , इतना है कि कुछ वर्णों (जैसे उद्धरण, रिक्त स्थान या यहां तक ​​कि newlines) के साथ फ़ाइल नाम अभी भी सही तरीके से संभाला जाता है।find-0

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.