पाइप किए गए इनपुट की प्रति पंक्ति एक बार एक कमांड निष्पादित करें?


162

मैं हर मैच के लिए एक बार जावा कमांड चलाना चाहता हूं ls | grep pattern -। इस मामले में, मुझे लगता है कि मैं कर सकता था, find pattern -exec java MyProg '{}' \;लेकिन मैं सामान्य मामले के बारे में उत्सुक हूं - क्या यह कहने का एक आसान तरीका है "मानक इनपुट की प्रत्येक पंक्ति के लिए एक बार कमांड चलाएं"? (मछली या बैश में)

जवाबों:


91

वही xargsकरता है।

... | xargs command

25
काफी नहीं। printf "foo bar\nbaz bat" | xargs echo wheeउपज देगा whee foo bar baz bat। शायद -Lया -nविकल्प जोड़ सकते हैं?
जैंडर

3
@ जेंडर प्रश्न सामान्य था, इसलिए मैंने सामान्य टूल दिया। सच है, आपको विशिष्ट परिस्थितियों के आधार पर विकल्पों के साथ इसके व्यवहार को समायोजित करना होगा।
कीथ

4
... | tr '\ n' '\ 0' | xargs -0
vrdhn

7
जैसे, "विशिष्ट परिस्थितियाँ जो प्रश्न का सही उत्तर देती हैं"। :)
Mattdm

7
यदि आप xargs के साथ ऐसा करने का उचित तरीका देखना चाहते हैं, तो नीचे मेरा जवाब देखें।
माइकल गोल्डस्मिन

167

स्वीकार किए गए उत्तर में सही विचार है, लेकिन कुंजी स्विच को पास xargsकरना है -n1, जिसका अर्थ है "आउटपुट की प्रति पंक्ति एक बार कमांड निष्पादित करें।"

cat file... | xargs -n1 command

या, एकल इनपुट फ़ाइल के लिए आप पाइप से catपूरी तरह से बच सकते हैं और बस साथ जा सकते हैं:

<file xargs -n1 command

1
ब्याज की भी क्षमता खाली नहीं होने xargsपर नहीं चलने की क्षमता है :: यदि मानक इनपुट में कोई भी गैर- stdinरिक्त स्थान --no-run-if-empty -rनहीं है, तो कमांड को न चलाएं। सामान्यतया, इनपुट न होने पर भी कमांड एक बार चलाया जाता है। यह विकल्प GNU एक्सटेंशन है।
रॉनन जौचेट

4
डाईउ अंदर लाइन का उपयोग कैसे करते हैं command?
बीटी

यह xargs का सही उपयोग है। बिना -n1 के, यह केवल उन कमांड पर काम करता है जो मापदंडों की सूची को कई इनवोकेशन के रूप में मानते हैं जो सभी नहीं करते हैं।
मास्टरएक्सिलो

3
प्रिंटफ "फू बार \ nbaz बल्ले" | xargs -n1 इको मट्ठे को शब्दों से विभाजित करते हैं और रेखाओं द्वारा नहीं
जिस्मो रानास

112

बैश या किसी अन्य बॉर्न-शैली के शेल (राख, ksh, zsh,…) में:

while read -r line; do command "$line"; done

read -rमानक इनपुट से एक पंक्ति पढ़ता है ( बैकस्लैश की व्याख्या readकिए बिना -r, आप ऐसा नहीं चाहते हैं)। इस प्रकार आप निम्नलिखित में से कोई भी कर सकते हैं:

$ command | while read -r line; do command "$line"; done  

$ while read -r line; do command "$line"; done <file

6
जब मैंने कोशिश की तो tail -f syslog | grep -e something -e somethingelse| while read line; do echo $line; doneयह काम नहीं किया। यह whileलूप में पाई गई फ़ाइल के साथ काम करता है tail -f, बस के साथ काम करता है , बस के साथ काम करता है grep, लेकिन दोनों पाइपों के साथ नहीं। देते विकल्प यह काम कर दियाgrep--line-buffered

यह तब भी काम करता है जब प्रत्येक पंक्ति को स्टडिन में भेजने की आवश्यकता होती है:command | while read -r line; do echo "$line" | command ; done
Den

21

मैं कीथ के साथ सहमत हूं, xargs नौकरी के लिए सबसे सामान्य उपकरण है।

मैं आमतौर पर एक 3 कदम दृष्टिकोण का उपयोग करता हूं।

  • जब तक आपके पास काम करने के लिए कुछ न हो, तब तक बुनियादी सामान न रखें
  • awk के साथ लाइन तैयार करें ताकि उसे सही सिंटैक्स मिले
  • तो xargs इसे निष्पादित करते हैं, शायद बैश की मदद से।

छोटे और तेज़ तरीके हैं, लेकिन यह तरीके लगभग हमेशा काम करते हैं।

एक सरल उदाहरण:

ls | 
grep xls | 
awk '{print "MyJavaProg --arg1 42 --arg2 "$1"\0"}' | 
xargs -0 bash -c

2 पहली पंक्तियों के साथ काम करने के लिए कुछ फ़ाइलों का चयन करता है, फिर awk निष्पादित करने के लिए एक कमांड के साथ एक अच्छा स्ट्रिंग तैयार करता है और कुछ तर्क और $ 1 पाइप से पहला स्तंभ इनपुट है। और अंत में मैं यह सुनिश्चित करता हूं कि xargs इस स्ट्रिंग को bash में भेजता है जो इसे निष्पादित करता है।

यह थोड़ा ज़्यादा है, लेकिन इस रेसिपी ने मुझे बहुत सारी जगहों पर मदद की है क्योंकि यह बहुत लचीली है।


6
ध्यान दें, xargs -0एक रिकॉर्ड विभाजक के रूप में अशक्त बाइट का उपयोग करता है, इसलिए आपका awk प्रिंट स्टेटमेंट होना चाहिएprintf("MyJavaProg --args \"%s\"\0",$1)
ग्लेन जैकमैन

@glenn: अशक्त चार को याद किया, जवाब अद्यतन करेगा
जोहान

@ जोहान कोई बड़ी बात नहीं है, लेकिन अगर आप इसका इस्तेमाल कर रहे awkहैं तो इसका पैटर्न मैच हो सकता है और grep उदाहरण के लिए छोड़ दें ,ls | awk '/xls/ {print...
एरिक रेनॉफ

15

GNU समानांतर उस तरह के कार्यों के लिए बनाया गया है। सबसे सरल उपयोग है:

cat stuff | grep pattern | parallel java MyProg

अधिक जानने के लिए इंट्रो वीडियो देखें: http://www.youtube.com/watch?v=OpaiGYxkSuQ


1
catयहाँ के लिए कोई वास्तविक जरूरत नहीं है क्योंकि grepसीधे फाइल को पढ़ सकते हैं
एरिक रेनॉफ


1
लिंक के लिए धन्यवाद, मैं जरूरी नहीं मानता कि यह पढ़ना आसान है, लेकिन यह जानना अच्छा है कि इसे ध्यान से माना गया था। मैं केवल अब थोड़ा वक्रोक्ति करना चाहूंगा कि लिंक वास्तव में यहां लागू नहीं होता है क्योंकि विकल्प वास्तव में नहीं है, < stuff grep patternलेकिन grep pattern stuffसभी के लिए आवश्यक पुनर्निर्देशन या बिल्ली के साथ नहीं है। फिर भी, यह आपके तर्क को भौतिक रूप से नहीं बदलता है और यदि आपको लगता है कि यह एक पाइप में चीजों को हमेशा उपयोग करने के लिए स्पष्ट है जो आपके साथ शुरू होता है cat, तो आपके लिए शक्ति
एरिक रेनॉफ

8

इसके अलावा, while readफिश शेल में लूप (मुझे लगता है कि आप फिश शेल चाहते हैं, यह देखते हुए कि आपने टैग का इस्तेमाल किया है )।

command | while read line
    command $line
end

कुछ बिंदुओं पर ध्यान दें।

  • read-rतर्क नहीं लेता है, और यह आपके बैकस्लैश की व्याख्या नहीं करता है, ताकि सबसे आम उपयोग के मामले को आसान बनाया जा सके।
  • आपको कोसने की आवश्यकता नहीं है $line, जैसे कि बैश के विपरीत, मछली रिक्त स्थान द्वारा अलग-अलग चर नहीं करती है।
  • commandअपने आप में एक वाक्यविन्यास त्रुटि है (प्लेसहोल्डर तर्कों के ऐसे उपयोग को पकड़ने के लिए)। इसे असली कमांड से बदलें।

whileके साथ doऔर के doneबजाय युग्मित करने की आवश्यकता नहीं है end?
aff

@ यदि यह विशेष रूप से मछली के खोल के बारे में है, जिसमें अलग-अलग वाक्यविन्यास हैं।
कोनराड बोरोस्की

आह, तो यह है कि मछली का क्या मतलब है।
एएफएफ

6

यदि आपको यह नियंत्रित करने की आवश्यकता है कि वास्तव में इनपुट तर्क आपकी कमांड लाइन में कहां डाला गया है या यदि आपको इसे कई बार दोहराने की आवश्यकता है, तो आपको उपयोग करने की आवश्यकता है xargs -I{}

उदाहरण 1

another_folderवर्तमान निर्देशिका में सबफ़ोल्डर्स को मिरर करने के लिए एक खाली फ़ोल्डर संरचना बनाएँ :

    ls -1d ./*/ | xargs -I{} mkdir another_folder/{}
उदाहरण # 2

स्टड से आने वाली फ़ाइल सूची पर एक ऑपरेशन लागू करें, इस मामले में .htmlएक .bakएक्सटेंशन संलग्न करके प्रत्येक फ़ाइल की एक प्रति बनाएं :

    find . -iname "*.html" | xargs -I{} cp {} {}.bak

xargsMacOS / BSD के लिए मैन पेज से :

 -I replstr
         Execute utility for each input line, replacing one or more occurrences of
         replstr in up to replacements (or 5 if no -R flag is specified) arguments
         to utility with the entire line of input.  The resulting arguments, after
         replacement is done, will not be allowed to grow beyond 255 bytes; this is
         implemented by concatenating as much of the argument containing replstr as
         possible, to the constructed arguments to utility, up to 255 bytes.  The
         255 byte limit does not apply to arguments to utility which do not contain
         replstr, and furthermore, no replacement will be done on utility itself.
         Implies -x.

लिनक्स xargsमैन पेज :

   -I replace-str
          Replace  occurrences of replace-str in the initial-
          arguments with names read from standard input.  Al
          so,  unquoted  blanks do not terminate input items;
          instead the separator  is  the  newline  character.
          Implies -x and -L 1.

1

संभावित असंगत इनपुट से निपटने के दौरान, मैं इसे चलाने से पहले दृश्य निरीक्षण के लिए लाइन द्वारा पूरी नौकरी को 'वर्तनी से बाहर' देखना पसंद करता हूं (विशेषकर जब यह लोगों के मेलबॉक्स को साफ करने जैसा कुछ विनाशकारी हो)।

तो मैं जो कुछ भी करता हूं, वह मापदंडों की एक सूची उत्पन्न करता है (जैसे। उपयोगकर्ता नाम), इसे एक-एक-रिकॉर्ड-प्रति-पंक्ति फैशन की फ़ाइल में फ़ीड करें, जैसे:

johndoe  
jamessmith  
janebrown  

तब मैं सूची को खोलता हूं vim, और इसे खोज के साथ जोड़ देता हूं और अभिव्यक्तियों को बदल देता हूं जब तक कि मुझे पूर्ण आदेशों की एक सूची न मिल जाए, जिन्हें निष्पादित करने की आवश्यकता है:

/bin/rm -fr /home/johndoe  
/bin/rm -fr /home/jamessmith 

इस तरह अगर आपका रेगेक्स अधूरा है, तो आप देखेंगे कि किस कमांड में संभावित समस्याएं होंगी (यानी। /bin/rm -fr johnnyo connor)। इस तरह से आप अपने रेगेक्स को पूर्ववत कर सकते हैं, और इसे फिर से इसके अधिक विश्वसनीय संस्करण के साथ आज़मा सकते हैं। इसके लिए नेम मैनरिंग बदनाम है, क्योंकि वान गाग, ओ'कॉनर्स, सेंट क्लेयर, स्मिथ-वेसन जैसे सभी किनारे मामलों की देखभाल करना मुश्किल है।

इसमें ऐसा करने के set hlsearchलिए उपयोगी है vim, क्योंकि यह सभी मैचों को उजागर करेगा, इसलिए आप आसानी से स्पॉट कर सकते हैं यदि यह मेल नहीं खाता है, या अनपेक्षित तरीके से मेल खाता है।

एक बार जब आपका रेगेक्स परिपूर्ण होता है और यह उन सभी मामलों को पकड़ लेता है, जिनके बारे में आप सोच सकते हैं / सोच सकते हैं, तो मैं इसे आमतौर पर एक सेड अभिव्यक्ति में बदल देता हूं, ताकि यह दूसरे रन के लिए पूरी तरह से स्वचालित हो सके।

ऐसे मामलों के लिए जहां इनपुट की लाइनों की संख्या आपको एक दृश्य निरीक्षण करने से रोकती है, मैं अत्यधिक कमांड को स्क्रीन पर निष्पादित करने की सलाह देता हूं (या बेहतर अभी तक, एक लॉग) इसे निष्पादित करने से पहले, इसलिए यदि यह गलत हो जाता है, तो आप वास्तव में जानते हैं कि किस कमांड के कारण हुआ असफल होना। फिर आप अपने मूल रेगेक्स पर वापस जा सकते हैं और एक बार फिर समायोजित कर सकते हैं।


0

यदि कोई प्रोग्राम पाइप को अनदेखा करता है, लेकिन फ़ाइलों को तर्क के रूप में स्वीकार करता है, तो आप इसे केवल विशेष फ़ाइल को इंगित कर सकते हैं /dev/stdin

मैं जावा से परिचित नहीं हूँ, लेकिन यहाँ एक उदाहरण है कि आप इसे कैसे करते हैं:

$ echo $'pwd \n cd / \n pwd' |bash /dev/stdin
/home/rolf
/

$ \nको नए समाचारों में अनुवाद करने के लिए आवश्यक है। मुझे यकीन नहीं है कि क्यों।


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