2013-02-22 11 views
11

बिना मेरे पास एक स्क्रिप्ट है जो केवल stdout पर डेटा लिखती है। मुझे इसे कई फाइलों के लिए चलाने और प्रत्येक इनपुट फ़ाइल के लिए एक अलग आउटपुट फ़ाइल उत्पन्न करने की आवश्यकता है और मैं सोच रहा था कि इसके लिए find -exec का उपयोग कैसे करें। इसलिए मैं मूल रूप से इस बात का कई वेरिएंट की कोशिश की (मैं सिर्फ testability प्रयोजनों के लिए cat द्वारा स्क्रिप्ट की जगह):find -exec के साथ stdout को रीडायरेक्ट करना और नया खोल

लगता है * प्रकार -exec बिल्ली च "{}"> "{} .stdout" \;

लेकिन यह काम नहीं कर सका क्योंकि सभी डेटा को एक फ़ाइल में लिखा जा रहा था जिसका शाब्दिक नाम {}.stdout है।

आखिरकार, मैं इसके साथ काम कर सकता है:

खोज * प्रकार च -exec श -c "बिल्ली {}> {} .stdout" \;

लेकिन जब इस नवीनतम रूप cat साथ अच्छी तरह से काम करता है, मेरी स्क्रिप्ट की आवश्यकता है वातावरण चर कई आरंभीकरण स्क्रिप्ट के माध्यम से भरी हुई है, इस प्रकार मैं के साथ अंत:

खोज * प्रकार च -exec श -c " initscript1; initscript2; ...; myscript {}> {} .stdout "\;

जो कचरा लगता है क्योंकि मेरे पास मेरे वर्तमान खोल में पहले से ही सबकुछ शुरू हुआ है।

क्या find के साथ ऐसा करने का कोई बेहतर तरीका है? अन्य एक-लाइनर का स्वागत है।

+2

यदि वे आपके मूल खोल में प्रारंभ होते हैं, लेकिन उपशीर्षक में सेट नहीं होते हैं, तो वे पर्यावरण चर नहीं होते हैं। अपनी initscripts के शीर्ष पर 'set -a' लिखें। –

+0

क्या अंतिम उदाहरण आप सही देते हैं, या आदेश है: 'ढूंढें। -type f -exec sh -c "। initscript1; initscript2; ...; myscript {}> {} .stdout" \; '(केवल 'initscript1' का आह्वान करने के बजाय, क्या आप वास्तव में' initscript1' को कॉल कर रहे हैं, यानी आप डॉट कमांड के साथ फ़ाइल को सोर्स कर रहे हैं)। –

उत्तर

5

एक सरल समाधान अपनी स्क्रिप्ट के चारों ओर एक आवरण डाल करने के लिए होगा:

#!/bin/sh 

myscript "$1" > "$1.stdout" 

यह myscript2 कॉल और ढूंढें साथ यह आह्वान:

find . -type f -exec myscript2 {} \; 

ध्यान दें कि हालांकि के अधिकांश प्रयोगों पाते हैं कि आप करने की अनुमति जो कुछ आपने किया है, वह करें तकनीकी रूप से खोज का व्यवहार अनिर्दिष्ट है यदि आप {}-exec की तर्क सूची में एक से अधिक बार उपयोग करते हैं।

+2

लेकिन 'खोज' मैनुअल में, कहीं-'-exec' में कहा जाता है कि: _ स्ट्रिंग' {} 'को प्रतिस्थापित किया जा रहा है, वर्तमान फ़ाइल नाम को हर जगह संसाधित किया जा रहा है, यह कमांड के तर्कों में होता है, न केवल तर्कों में अकेले है, जैसा कि find._ [link] के कुछ संस्करणों में है (http://unixhelp.ed.ac.uk/CGI/man-cgi?find)। फिर भी, कामकाज के लिए धन्यवाद। – jserras

+3

'खोज' राज्य के आपके विशेष कार्यान्वयन के लिए मैनुअल यह काम करता है, लेकिन मानक पढ़ता है: 'यदि एक से अधिक तर्क केवल दो अक्षर होते हैं "{}" मौजूद है, तो व्यवहार अनिर्दिष्ट है।' यह एक बड़ा सौदा नहीं है , लेकिन ऐसा कुछ है जो आपको जला सकता है (जिस बिंदु पर यह अचानक एक बड़ा सौदा बन जाता है!) –

+3

एक और महत्वपूर्ण नुकसान यह है कि '-exec sh -c "myscript {}> {} .stdout" \; 'कारण हो सकता है शत्रुतापूर्ण फ़ाइल नामों के चेहरे में मनमाने ढंग से कोड निष्पादन। यह '-exec sh -c' myscript "$ 1"> "$ 1.stdout" 'sh {} \; 'करने के लिए और अधिक सुरक्षित है। – jilles

2

आप इसे eval के साथ कर सकते हैं। यह बदसूरत हो सकता है, लेकिन इसके लिए एक खोल स्क्रिप्ट बनाना है। इसके अलावा, यह सब एक पंक्ति पर है। उदाहरण के लिए

find -type f -exec bash -c "eval md5sum {} > {}.sum " \; 
+0

'bash -c' यहां गोमांस है, 'eval' वास्तव में कुछ भी उपयोगी नहीं कर रहा है। लेकिन आप खोल से परहेज नहीं कर रहे हैं। – tripleee

+0

यदि आप 'eval' लेते हैं तो मैं सोच रहा हूं कि यह वास्तव में स्वीकार्य उत्तर होना चाहिए, भले ही ओपी एक खोल से बचने के लिए lilke। (किसी स्क्रिप्ट को एक अलग फ़ाइल में डालने पर वैसे भी एक स्क्रिप्ट बनाता है जब भी वह स्क्रिप्ट चलाता है। ओपी क्या पूछ रहा है वास्तव में संभव नहीं है।) – tripleee

+0

'eval' सक्रिय रूप से खतरनाक है। अगर आपके पास फ़ाइल नाम है जिसमें '$ (आरएम-आरएफ $ HOME)' है, तो यह ** बहुत ** बुरी खबर होगी। –

2

यदि आप निर्यात अपने वातावरण चर, वे पहले से ही बच्चे को खोल में मौजूद हो जाएगा (आप bash -c बजाय sh -c, का उपयोग करें और अगर आपके माता-पिता खोल ही है, पार्टी है, तो आप भी कर सकते हैं निर्यात पैरेंट खोल में फ़ंक्शन करें और उन्हें बच्चे में उपयोग करने योग्य बनाएं; export -f देखें)।

इसके अलावा, -exec ... {} + उपयोग करके, आप छोटी संभव जरूरत संख्या के गोले की संख्या कमांड लाइन पर सभी तर्क पारित करने के लिए सीमित कर सकते हैं:

set -a # turn on automatic export of all variables 
source initscript1 
source initscript2 

# pass as many filenames as possible to each sh -c, iterating over them directly 
find * -name '*.stdout' -prune -o -type f \ 
    -exec sh -c 'for arg; do myscript "$arg" > "${arg}.stdout"' _ {} + 

वैकल्पिक रूप से, आपको केवल अपनी वर्तमान में निष्पादन प्रदर्शन कर सकते हैं सीधे शैल:

while IFS= read -r -d '' filename; do 
    myscript "$filename" >"${filename}.out" 
done < <(find * -name '*.stdout' -prune -o -type f -print0) 

देखें UsingFind सुरक्षित रूप से चर्चा और सही ढंग से find के माध्यम से थोक कार्यों का निष्पादन; और BashFAQ #24 प्रक्रिया प्रतिस्थापन (<(...) वाक्यविन्यास) के उपयोग पर चर्चा करने के लिए यह सुनिश्चित करने के लिए कि पैरेंट शैल में संचालन किया जाता है।

+0

आह्वान sh के लिए '_' के रूप में' 0' का उपयोग करना थोड़ा मोटापा है! –

+0

@ विलियम पर्सेल, यह एक आम मुहावरे है - यदि आप चाहें तो लिंक पा सकते हैं। ('_' कुछ अन्य भाषाओं में पाइथन जैसे पारंपरिक अप्रयुक्त/प्लेसहोल्डर मूल्य भी है, लेकिन मेरी समझ यह है कि यह पहले शेल में आम था)। –

+0

मैंने इसे देखा है और perl में उपयोग किया है, लेकिन इस सेटिंग में कभी नहीं। मैं इसे अनदेखा करता हूं और $ 0 को {} सेट करता हूं, जो शायद एक बहुत ही खराब अभ्यास है! –

संबंधित मुद्दे