खाली होने पर इटरेट फाइल लिस्ट को बैश करें


33

मैंने सोचा कि यह सरल होगा - लेकिन यह मेरी अपेक्षा से अधिक जटिल साबित हो रहा है।

मैं एक विशेष प्रकार की सभी फाइलों को एक निर्देशिका में बदलना चाहता हूं, इसलिए मैं यह लिखता हूं:

#!/bin/bash

for fname in *.zip ; do
   echo current file is ${fname}
done

यह तब तक काम करता है जब तक कि निर्देशिका में कम से कम एक मिलान फ़ाइल हो। हालाँकि अगर कोई मेल नहीं होती है, तो मुझे यह मिलता है:

current file is *.zip

मैंने तब कोशिश की:

#!/bin/bash

FILES=`ls *.zip`
for fname in "${FILES}" ; do
    echo current file is ${fname}
done

लूप का शरीर निष्पादित नहीं करता है जब कोई फाइल नहीं होती है, तो मुझे ls से एक त्रुटि मिलती है:

ls: *.zip: No such file or directory

मैं एक लूप कैसे लिखता हूं जो साफ-सफाई से बिना मिलान वाली फाइलों को संभालता है?


7
shopt -s nullglobलूप के लिए दौड़ने से पहले जोड़ें ।
cuonglm 14

@cuolnglm: spsily इस परिणाम में ls इस आरएचईएल 5 बॉक्स पर खाली सूची के बजाय एग्जीक्यूटिव स्क्रिप्ट का नाम लौटाता है (अगर 3.2.25) मैं FILES=ls * .zip ; for fname in "${FILES}"...करता हूं, लेकिन यह अपेक्षित रूप से काम नहीं करता हैfor fname in *.zip ; do....
सिम्बियन

3
का उपयोग करें for file in *.zip, नहीं `ls ...`। @ cuonglm का सुझाव इतना है कि *.zipपैटर्न कुछ भी फ़ाइल से मेल नहीं खाने पर कुछ भी नहीं फैलता है। lsतर्कों के बिना वर्तमान निर्देशिका को सूचीबद्ध करता है।
स्टीफन चेजेलस

1
यह सवाल चर्चा करता है कि lsआम तौर पर बचाए जाने के उत्पादन को पार्स क्यों किया जाता हैls : पार्स क्यों नहीं ? ; उस पृष्ठ के शीर्ष के पास लिंक को बशगाइड के पारसिंगल लेख के साथ भी देखें।
PM 2Ring 11

जवाबों:


34

में bash, आप nullglobविकल्प सेट कर सकते हैं ताकि एक पैटर्न जो "गायब हो जाता है" से मेल खाता हो, बल्कि एक शाब्दिक स्ट्रिंग के रूप में माना जाता है:

shopt -s nullglob
for fname in *.zip ; do
   echo "current file is ${fname}"
done

POSIX शेल स्क्रिप्ट में, आप बस यह सत्यापित करते हैं कि fnameमौजूद है (और उसी समय के साथ [ -f ], यह जांचें कि यह एक नियमित फ़ाइल है (या नियमित फ़ाइल के लिए सिमलिंक) और अन्य प्रकार जैसे निर्देशिका / फीफो / डिवाइस ...):

for fname in *.zip; do
    [ -f "$fname" ] || continue
    printf '%s\n' "current file is $fname"
done

बदलें [ -f "$fname" ]के साथ [ -e "$fname" ] || [ -L "$fname ]अगर आप सब कुछ खत्म हो लूप करना चाहते हैं (गैर छिपा हुआ) फ़ाइलें जिसका नाम में समाप्त होता है .zipअपने प्रकार की परवाह किए बिना।

इसके *.zipसाथ बदलें .*.zip .zip *.zipयदि आप छिपी हुई फाइलों पर भी विचार करना चाहते हैं जिनके नाम में समाप्त होता है .zip


1
shopt -s nullglobउबंटू 17.04 पर मेरे लिए काम नहीं किया, लेकिन [ -f "$fname" ] || continueअच्छी तरह से काम किया।
कोपरपॉप

@koppor ऐसा लगता है कि आप वास्तव में उपयोग नहीं कर रहे हैं bash
शेपनर

2
set ./*                               #set the arg array to glob results
${2+":"} [ -e "$1" ] &&               #if more than one result skip the stat "$1"
printf "current file is %s\n" "$@"    #print the whole array at once

###or###

${2+":"} [ -e "$1" ] &&               #same kind of test
for    fname                          #iterate singly on $fname var for array
do     printf "file is %s\n" "$fname" #print each $fname for each iteration
done                                  

यहाँ एक टिप्पणी में आप एक समारोह में शामिल होने का उल्लेख करते हैं ...

file_fn()
    if     [ -e "$1" ] ||               #check if first argument exists
           [ -L "$1" ]                  #or else if it is at least a broken link
    then   for  f                       #if so iterate on "$f"
           do : something w/ "$f"
           done
    else   command <"${1-/dev/null}"    #only fail w/ error if at least one arg
    fi

 file_fn *

2

खोजने का उपयोग करें

export -f myshellfunc
find . -mindepth 1 -maxdepth 1 -type f -name '*.zip' -exec bash -c 'myshellfunc "$0"' {} \;

आप इसके लिए अपने शेल फंक्शन को ज़रूर export -fसे काम करें। अब findनिष्पादित करता है bashजो आपके शेल फ़ंक्शन को निष्पादित करता है, और केवल वर्तमान dir स्तर पर रहता है।


जो उपनिर्देशिकाओं के माध्यम से पुनरावृत्ति करता है, और मैं मैचों के लिए बैश फ़ंक्शन (स्क्रिप्ट नहीं) को लागू करना चाहता हूं।
सिम्बियन

@symcbean ने मुझे सिंगल डायर तक सीमित रखने और बैश कार्यों को संभालने के लिए संपादित किया है
Dani_l

-3

के बजाय:

FILES=`ls *.zip`

प्रयत्न:

FILES=`ls * | grep *.zip`

इस तरह यदि ls विफल हो जाता है (जो आपके मामले में ऐसा करता है) तो यह विफल आउटपुट को पकड़ लेगा और एक रिक्त चर के रूप में वापस आ जाएगा।

current file is      <---Blank Here

आप इसे "नो फाइल फाउंड" वापस करने के लिए कुछ तर्क जोड़ सकते हैं

#!/bin/bash

FILES=`ls * | grep *.zip`
if [[ $? == "0" ]]; then
    for fname in "$FILES" ; do
        echo current file is $fname
    done
else
    echo "No Files Found"
fi

इस तरह यदि पिछली कमांड सफल हो गई (0 मान के साथ बाहर) तो यह वर्तमान फ़ाइल को प्रिंट करेगी, अन्यथा यह "नई फाइलें" प्रिंट करेगी


1
मुझे लगता है कि grepएक बेहतर उपकरण ( find) का उपयोग करके समस्या को ठीक करने की कोशिश करने या वर्तमान समाधान के लिए प्रासंगिक सेटिंग को बदलने के बजाय (साथ shopt -s nullglob)
थॉमस बरुचेल

1
उनके मूल पोस्ट पर ओपी की टिप्पणी के अनुसार shopt -s nullglobकाम नहीं करता है। मैंने findअपने उत्तर की पुष्टि करते हुए कोशिश की और यह विफल रहा। मुझे लगता है कि निर्यात की बात के कारण दानी ने कहा।
किप के
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.