एक निर्देशिका में फ़ाइलों के माध्यम से पुनरावृत्ति


15

एक निर्देशिका में फ़ाइलों के माध्यम से पुनरावृत्ति आसानी से किया जा सकता है:

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

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

while read line; do [...]; done < <(find . -type f)

हालाँकि, ऐसा लगता है कि यह अस्पष्ट वर्ण वाली फ़ाइलों के लिए काम नहीं करता है:

$ touch $'a\nb'
$ find . -type f
./a?b

क्या कोई विकल्प है जो ऐसे अस्पष्ट पात्रों को अच्छी तरह से संभालता है?


1
find ... -exec bash -c 'echo filename is in \$0: "$0"' {} \;यह करने के लिए एक बेहतर तरीका है।
jw013

आप इस का समाधान, और अपने मूल डिजाइन रखने के लिए, अपने को बदलने के द्वारा कर सकते हैं read lineकरने के लिए IFS= read -r line। एकमात्र चरित्र जो इसे तोड़ देगा, फिर एक नई रेखा है।
पैट्रिक

1
@ पैट्रिक, लेकिन फ़ाइल नाम में नई सीमाएँ हो सकती हैं। इसलिए -d $'\0'बेहतर है।

जवाबों:


7

सुरक्षित केfind लिए एक और उपयोग :

while IFS= read -r -d '' -u 9
do
    [Do something with "$REPLY"]
done 9< <( find . -type f -exec printf '%s\0' {} + )

(यह किसी भी POSIX के साथ काम करता है find, लेकिन शेल भाग को bash की आवश्यकता होती है। * BSD और GNU के साथ, आप -print0इसके बजाय उपयोग कर सकते हैं -exec printf '%s\0' {} +, यह थोड़ा तेज़ होगा।)

यह लूप के भीतर मानक इनपुट का उपयोग करना संभव बनाता है, और यह किसी भी पथ के साथ काम करता है ।


1
क्योंकि मुझे इसे देखना था: "पढ़िए ... यदि कोई नाम नहीं दिया गया है, तो पढ़ी गई रेखा चर चर को सौंपा गया है।" तोdo echo "Filename is '$REPLY'"
एंड्रयू

9

यह करना उतना ही सरल है:

find -exec sh -c 'inline script "$0"' {} \;

या ...

find -exec executable_script {} \;

5

शेल ग्लोबिंग का उपयोग करने के लिए सबसे सरल (अभी तक सुरक्षित) तरीका है:

$ for f in *; do printf ":%s:\n" "$f"; done 
:a b:
:c
d:
:-e:
:e  f:
h:

उप पुनर्निर्देशन को उपनिर्देशिका (बैश में) बनाने के लिए, आप globstarविकल्प का उपयोग कर सकते हैं ; dotglobउन फ़ाइलों से मिलान करने के लिए भी सेट करें जिनका नाम निम्नलिखित है .:

$ shopt -s globstar dotglob
$ for f in **/*; do printf ":%s:\n" "$f"; done 
:a b:
:c
d:
:-e:
:e  f:
:foo:
:foo/file1:
:foo/file two:
h:

4.2 को **/कोसने के लिए सावधान रहें, निर्देशिकाओं के प्रतीकात्मक लिंक में पुनरावृत्ति करता है। 4.3 के बाद से, **/केवल निर्देशिका में पुनरावृत्ति करता है, जैसे find

एक अन्य आम समाधान उपयोग करने के लिए है find -print0के साथ xargs -0:

$ touch -- 'a b' $'c\nd' $'e\tf' $'g\rh' '-e'
$ find . -type f -print0 | xargs -0 -I{} printf ":%s:\n" {}
h:/g
:./e    f:
:./a b:
:./-e:
:./c
d:

ध्यान दें कि h:/gफ़ाइल नाम में ए से वास्तव में सही है \r


4

अपने रीड लूप को कुछ हद तक करना थोड़ा मुश्किल है, लेकिन विशेष रूप से आपको इस तरह से कुछ करने की कोशिश करनी चाहिए ।

प्रासंगिक भाग:

while IFS= read -d $'\0' -r file ; do
        printf 'File found: %s\n' "$file"
done < <(find . -iname 'foo*' -print0)

यह findNUL वर्णों (0x00) द्वारा सीमांकित इसके उत्पादन को मुद्रित करने के लिए निर्देश देता है, और अन्य वर्णों के लिए भाग के रूप में बैकस्लैश को संभालने के बिना readएनयूएल-सीमांकित रेखाओं ( -d $'\0') को लाने के लिए ( -r) और लाइनों पर विभाजित किसी भी शब्द को न करें ( IFS=)। चूंकि 0x00 एक बाइट है जो यूनिक्स में फ़ाइलनाम या पथ में नहीं हो सकता है, यह आपकी सभी अजीब फ़ाइल समस्याओं को संभालना चाहिए।


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