2013-02-25 88 views
38

निम्न आदेश प्रयास:मैं प्रत्येक लूप के लिए बैश में फ़ाइल पथों को फिर से चलाने के लिए कैसे उपयोग करूं? मौजूदा निर्देशिका में सभी <code>*.txt</code> फ़ाइलों की गणना और एक एक करके उन्हें एक पर कार्रवाई करने के

for line in "find . -iname '*.txt'"; do 
    echo $line 
    ls -l $line; 
done 

क्यों मैं उद्धरण के बजाय निम्न त्रुटि ?:

ls: invalid option -- 'e' 
Try `ls --help' for more information. 

उत्तर

97

यहाँ फ़ाइलों पर पाश करने के लिए एक बेहतर तरीका है के रूप में यह फ़ाइल नामों में रिक्तियां और नई-पंक्तियों को संभालती है:

find . -type f -iname "*.txt" -print0 | while IFS= read -r -d $'\0' line; do 
    echo "$line" 
    ls -l "$line"  
done 
+9

+1 यह बेहतर नहीं है, यह सही है। – chepner

+0

मुझे यह काम करने में परेशानी हो रही है जब इस स्निपेट वाली स्क्रिप्ट को cronjob @reboot के भीतर से बुलाया जाता है। यह रीड कमांड के -d ध्वज के बारे में शिकायत करता है और फिर निष्पादित करने में विफल रहता है। अन्यथा यह बहुत अच्छा काम करता है। –

+8

बाश पर काम करता है, श पर नहीं। – Antzi

5

उपयोग command substitution मिलता है स्ट्रिंग के रूप में कमांड को पास करने के बजाए निष्पादित करने के लिए:

for line in $(find . -iname '*.txt'); do 
    echo $line 
    ls -l $line; 
done 
+1

अगर आपके पास "एकल फ़ाइल" नाम की एक फ़ाइल है, आपको लूप में दो '$ लाइनें' मिलेंगी। "फ़ाइल" के लिए एक "एकल" के लिए एक। – gcb

18

for -लोप प्रदान की गई स्ट्रिंग पर प्रत्येक (स्पेस से अलग) प्रविष्टि पर फिर से सक्रिय होगा।

आप वास्तव में find कमांड निष्पादित नहीं करते हैं, लेकिन इसे स्ट्रिंग के रूप में प्रदान करते हैं (जो for -loop द्वारा पुनरावृत्त हो जाता है)। दोहरे उद्धरण चिह्नों के बजाय या तो बैकटिक या $() का उपयोग करें:

for line in $(find . -iname '*.txt'); do 
    echo "$line" 
    ls -l "$line" 
done 

इसके अलावा, अगर आपकी फ़ाइल पथ/नाम रिक्ति इस विधि में विफल रहता है (रिक्ति द्वारा विभाजित प्रविष्टियों से अधिक for -loop दोहराता के बाद से)। इसके बजाय dogbanes answer में वर्णित विधि का उपयोग करना बेहतर है।

के रूप में कहा, सभी जगह अलग प्रविष्टियों से अधिक for line in "find . -iname '*.txt'"; दोहराता है, जो इस प्रकार हैं::

  • लगता है

  • अपने त्रुटि स्पष्ट करने के लिए।

  • -iname
  • '* .txt' (मुझे लगता है कि ...)

पहले दो (अवांछित व्यवहार के अलावा) एक त्रुटि में परिणाम नहीं है, लेकिन के रूप में यह कार्यान्वित तीसरे समस्याग्रस्त है :

ls -l -iname 

एकल वर्ण विकल्पों को जोड़ सकते हैं (बैश) आदेशों का एक बहुत है, इसलिए -iname-i -n -a -m -e के समान है। और voila: आपकी invalid option -- 'e' त्रुटि!

+9

यदि नाम में रिक्त स्थान हैं, तो यह सूची में दो अलग-अलग प्रविष्टियों के रूप में दिखाई देगा जो लूप के लिए पुनरावृत्त हो जाते हैं। – chepner

12

अधिक कॉम्पैक्ट संस्करण रिक्त स्थान और फ़ाइल नाम में नई-पंक्तियों के साथ काम:

find . -iname '*.txt' -exec sh -c 'echo "{}" ; ls -l "{}"' \; 
+0

पर यह मेरे लिए काम करता है यह उत्तर बहुत आसान है और यह बैश और सरल दोनों में काम करता है श (एश) गोले। – Alkaline