स्टड / स्टडआउट पुनर्निर्देशन के साथ xargs


21

मैं दौड़ना चाहूंगा:

./a.out < x.dat > x.ans

निर्देशिका A में प्रत्येक .dat फ़ाइल के लिए ।

ज़रूर, यह बैश / अजगर / जो भी स्क्रिप्ट द्वारा किया जा सकता है, लेकिन मुझे सेक्सी वन-लाइनर लिखना पसंद है। मैं सभी तक पहुँच सकता है (अभी भी बिना किसी रोक-टोक के):

ls A/*.dat | xargs -I file -a file ./a.out

लेकिन xags में -a प्रतिस्थापित-str 'फ़ाइल' को नहीं समझता है।

मदद के लिए शुक्रिया।


अन्य अच्छे उत्तरों के अलावा, आप GNU xargs के -a विकल्प का उपयोग कर सकते हैं।
जेम्स यंगमैन

जवाबों:


30

सबसे पहले, फ़ाइल सूची के रूप में आउटपुट का उपयोग न करेंls । शेल विस्तार या का उपयोग करें findLs + xargs के दुरुपयोग और उचित xargsउपयोग का एक उदाहरण के संभावित परिणामों के लिए नीचे देखें ।

1. सरल तरीका: के लिए पाश

यदि आप केवल फाइलों को अंडर प्रोसेस करना चाहते हैं A/, तो एक साधारण forलूप पर्याप्त होना चाहिए:

for file in A/*.dat; do ./a.out < "$file" > "${file%.dat}.ans"; done

2. प्री 1 क्यों नहीं   ls | xargs ?

यहाँ अगर आप का उपयोग कैसे बुरी चीजें बदल सकते हैं का एक उदाहरण है lsके साथ xargsकाम के लिए। इस परिदृश्य पर विचार करें:

  • पहले, चलो कुछ खाली फाइलें बनाते हैं:

    $ touch A/mypreciousfile.dat\ with\ junk\ at\ the\ end.dat
    $ touch A/mypreciousfile.dat
    $ touch A/mypreciousfile.dat.ans
    
  • फ़ाइलें देखें और उनमें कुछ भी नहीं है:

    $ ls -1 A/
    mypreciousfile.dat
    mypreciousfile.dat with junk at the end.dat
    mypreciousfile.dat.ans
    
    $ cat A/*
    
  • मैजिक कमांड का उपयोग करके चलाएं xargs:

    $ ls A/*.dat | xargs -I file sh -c "echo TRICKED > file.ans"
    
  • परिणाम:

    $ cat A/mypreciousfile.dat
    TRICKED with junk at the end.dat.ans
    
    $ cat A/mypreciousfile.dat.ans
    TRICKED
    

तो आप अभी mypreciousfile.datऔर दोनों को अधिलेखित करने में कामयाब रहे हैं mypreciousfile.dat.ans। यदि उन फ़ाइलों में कोई सामग्री होती है, तो उसे मिटा दिया जाएगा।


2. का उपयोग करना   xargs : के साथ उचित तरीका है  find 

यदि आप उपयोग करने पर जोर देना चाहते हैं xargs, तो -0(शून्य-समाप्त नाम) का उपयोग करें:

find A/ -name "*.dat" -type f -print0 | xargs -0 -I file sh -c './a.out < "file" > "file.ans"'

दो बातें नोटिस करें:

  1. इस तरह से आप फ़ाइलों को .dat.ansसमाप्त कर देंगे ;
  2. यह टूट जाएगा यदि कुछ फ़ाइल नाम में उद्धरण चिह्न ( ") हो।

दोनों मुद्दों को विभिन्न तरीकों से हल किया जा सकता है:

find A/ -name "*.dat" -type f -print0 | xargs -0 -L 1 bash -c './a.out < "$0" > "${0%dat}ans"'

3. सब भीतर किया find ... -exec

 find A/ -name "*.dat" -type f -exec sh -c './a.out < "{}" > "{}.ans"' \;

यह, फिर से, .dat.ansफ़ाइलों का उत्पादन करता है और अगर फ़ाइल के नाम होते हैं तो टूट जाएगा "। इसके बारे में जाने के लिए, bashइसे लागू करने के तरीके का उपयोग करें और इसे बदलें:

 find A/ -name "*.dat" -type f -exec bash -c './a.out < "$0" > "${0%dat}ans"' {} \;

+1, ls के आउटपुट को पार्स न करने के उल्लेख के लिए।
रहमू

2
ऑप्शन 2 तब टूटता है जब फाइलनाम में "
थिटॉन

2
बहुत अच्छी बात, धन्यवाद! मैं उसी हिसाब से अपडेट करूंगा।
rozcietrzewiacz

मैं केवल उल्लेख करना चाहता हूं, कि अगर zshशेल के रूप में उपयोग किया जाता है (और SH_WORD_SPLIT सेट नहीं है), सभी खराब विशेष मामलों (सफेद स्थान, "फ़ाइल नाम आदि में) पर विचार करने की आवश्यकता नहीं है। for file in A/*.dat; do ./a.out < $file > ${file%.dat}.ans ; doneसभी मामलों में तुच्छ काम करता है।
jofel

-1 क्योंकि मैं यह पता लगाने की कोशिश कर रहा हूं कि स्टैर्ड के साथ एक्सगार्स कैसे करें और मेरे सवाल का फाइलों या कुछ भी नहीं है find
मेहरदाद

2

ऐसा कुछ करने का प्रयास करें (आपके द्वारा उपयोग किए जाने वाले शेल के आधार पर सिंटैक्स थोड़ा भिन्न हो सकता है):

$ for i in $(find A/ -name \*.dat); do ./a.out < ${i} > ${i%.dat}.ans; done


वह काम नहीं करेगा। यह सामान पर काम करने की कोशिश करेगा somefile.dat.datऔर सभी आउटपुट को एक फ़ाइल में रीडायरेक्ट करेगा।
rozcietrzewiacz

आप सही हे। मैंने इसे ठीक करने के लिए समाधान संपादित किया।
रहमु ah

ठीक है - लगभग अच्छा :) बस somefile.dat.ansआउटपुट सामान इतना अच्छा नहीं लगेगा।
रोज़ज़ेट्रिएवेज़ेज़ ऑक्ट

1
संपादित! मुझे '%' के बारे में नहीं पता था। यह एक आकर्षण की तरह काम करता है, टिप के लिए धन्यवाद।
रहमू

1
जोड़ना एक -type fileअच्छा होगा (नहीं < directory), और यह असामान्य-फ़ाइल नाम-परी को दुखी करता है।
Mat

2

सरल पैटर्न के लिए, लूप के लिए उपयुक्त है:

for file in A/*.dat; do
    ./a.out < "${file}" > "${file%.dat}.ans" # Never forget the QUOTES!
done

अधिक जटिल मामलों के लिए जहां आपको फाइलों को सूचीबद्ध करने के लिए एक और उपयोगिता की आवश्यकता होती है (zsh या bash 4 में शक्तिशाली पर्याप्त पैटर्न हैं जो आपको शायद ही कभी मिलनी चाहिए, लेकिन यदि आप POSIX शेल में रहना चाहते हैं या डैश जैसे तेज़ शेल का उपयोग करना चाहते हैं, तो आपको किसी भी चीज़ की आवश्यकता होगी गैर-तुच्छ), जबकि पढ़ा सबसे उपयुक्त है:

find A -name '*.dat' -print | while IFS= read -r file; do
   ./a.out < "${file}" > "${file%.dat}.ans" # Never forget the QUOTES!
done

यह रिक्त स्थान को हैंडल करेगा, क्योंकि रीड (डिफ़ॉल्ट रूप से) लाइन-ओरिएंटेड है। यह न्यूलाइन्स को हैंडल नहीं करेगा और यह बैकस्लैश को हैंडल नहीं करेगा, क्योंकि डिफॉल्ट रूप से यह एस्केप सीक्वेंस की व्याख्या करता है (जो वास्तव में आपको एक न्यूलाइन में पास करने की अनुमति देता है, लेकिन यह पता नहीं लगा सकता है कि प्रारूप)। कई गोले में -0पढ़ने का विकल्प होता है ताकि आप सभी पात्रों को संभाल सकें, लेकिन दुर्भाग्य से यह POSIX नहीं है।


2

GNU समानांतर का उपयोग करें:

parallel ./a.out "<{} >{.}.ans" ::: A/*.dat

जोड़ा गया बोनस: आप समानांतर में किया गया प्रसंस्करण प्राप्त करते हैं।

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


1

मुझे लगता है कि आपको xargs में कम से कम शेल आमंत्रण की आवश्यकता है:

ls A/*.dat | xargs -I file sh -c "./a.out < file > file.ans"

संपादित करें: यह ध्यान दिया जाना चाहिए कि फ़ाइल नाम व्हाट्सएप होने पर यह दृष्टिकोण काम नहीं करता है। काम नहीं कर सकता। यहां तक ​​कि अगर आपने xargs को रिक्त स्थान को सही ढंग से समझने के लिए -0 और xargs -0 का उपयोग किया है, तो -c शेल कॉल उन पर क्रॉक करेगा। हालांकि, ओपी ने स्पष्ट रूप से एक xargs समाधान के लिए कहा, और यह सबसे अच्छा xargs समाधान है जिसके साथ मैं आया था। यदि फ़ाइल नाम में व्हाट्सएप एक मुद्दा हो सकता है, तो फाइंड -सेक्स या शेल लूप का उपयोग करें।



@rozcietrzewiacz: सामान्य तौर पर, निश्चित रूप से, लेकिन मुझे लगता है कि कोई व्यक्ति xargs को करने की कोशिश कर रहा है, यह जानता है। चूंकि ये फ़ाइलनाम एक और शेल विस्तार से गुजरते हैं, इसलिए उन्हें वैसे भी अच्छी तरह से व्यवहार करना होगा।
थिटॉन

1
आप शेल विस्तार के बारे में गलत हैं। lsबच निकलने के बिना रिक्त स्थान जैसी चीजों का उत्पादन करता है और यही समस्या है।
rozcietrzewiacz

@rozcietrzewiacz: हां, मैं उस समस्या को समझता हूं। अब बस मान लीजिए कि आप इन स्थानों से ठीक से बच जाएंगे और उन्हें xargs में प्राप्त कर लेंगे: उन्हें sh -c string में बदल दिया जाता है, to -izes को -c string, और सब कुछ टूट जाता है।
थिटॉन

हाँ। अब आप देखें, पार्सिंग lsकरना अच्छा नहीं है। लेकिन सुरक्षित रूप से खोज के साथ उपयोग किया xargs जा सकता है - मेरे उत्तर में सुझाव नंबर 2 देखें।
rozcietrzewiacz

1

इसे जटिल करने की कोई आवश्यकता नहीं है। आप इसे forलूप के साथ कर सकते हैं :

for file in A/*.dat; do
  ./a.out < "$file" >"${file%.dat}.ans"
done

${file%.dat}.ansबिट निकाल देंगे .datमें फ़ाइल नाम से फ़ाइल नाम प्रत्यय $fileऔर इसके बजाय जोड़ने .ansसमाप्त करने के लिए।

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