फ़ाइल नामों के माध्यम से लूप कैसे खोजें?


223
x=$(find . -name "*.txt")
echo $x

अगर मैं बैश शेल में कोड के उपरोक्त भाग को चलाता हूं, तो मुझे जो मिलता है वह एक स्ट्रिंग है जिसमें कई फ़ाइल नाम रिक्त होते हैं, सूची नहीं।

बेशक, मैं सूची पाने के लिए उन्हें खाली करके अलग कर सकता हूं, लेकिन मुझे यकीन है कि ऐसा करने का एक बेहतर तरीका है।

तो एक findकमांड के परिणामों के माध्यम से लूप का सबसे अच्छा तरीका क्या है ?


3
फ़ाइल नामों पर लूप करने का सबसे अच्छा तरीका इस बात पर काफी हद तक निर्भर करता है कि आप वास्तव में इसके साथ क्या करना चाहते हैं, लेकिन जब तक आप गारंटी नहीं दे सकते हैं कि उनके नाम पर कोई भी व्हाट्सएप नहीं है, यह ऐसा करने का एक शानदार तरीका नहीं है। तो क्या आप फ़ाइलों पर पाशन करना चाहते हैं?
केविन

1
इनाम के बारे में : यहां मुख्य विचार एक विहित उत्तर प्राप्त करना है जो सभी संभावित मामलों को कवर करता है (नई लाइनों, समस्याग्रस्त पात्रों के साथ फ़ाइल नाम ...)। विचार तब कुछ सामान करने के लिए इन फ़ाइल नामों का उपयोग करना है (किसी अन्य कमांड को कॉल करें, कुछ नाम बदलें ...)। धन्यवाद!
फेडोरक्वी 'एसओ ने

यह मत भूलो कि एक फ़ाइल या एक फ़ोल्डर नाम में "। Txt" हो सकता है जिसके बाद स्थान और एक अन्य स्ट्रिंग हो सकती है, उदाहरण "something.txt something" या "something.txt"
याह्या याह्याऊ

सरणी का उपयोग करें, var नहीं x=( $(find . -name "*.txt") ); echo "${x[@]}"तब आप लूप के माध्यम सेfor item in "${x[@]}"; { echo "$item"; }
इवान

जवाबों:


392

TL; DR: यदि आप यहाँ सबसे सही उत्तर के लिए हैं, तो आप शायद मेरी व्यक्तिगत पसंद चाहते हैं, find . -name '*.txt' -exec process {} \;(इस पोस्ट के नीचे देखें)। यदि आपके पास समय है, तो कई अलग-अलग तरीकों और उनमें से अधिकांश के साथ समस्याओं को देखने के लिए बाकी के माध्यम से पढ़ें।


पूरा जवाब:

सबसे अच्छा तरीका इस बात पर निर्भर करता है कि आप क्या करना चाहते हैं, लेकिन यहां कुछ विकल्प हैं। जब तक सबट्री में किसी फाइल या फोल्डर में व्हाट्सएप न हो, तब तक आप फाइलों पर सिर्फ लूप कर सकते हैं:

for i in $x; do # Not recommended, will break on whitespace
    process "$i"
done

मार्जिन बेहतर, अस्थायी चर को काटें x:

for i in $(find -name \*.txt); do # Not recommended, will break on whitespace
    process "$i"
done

जब आप कर सकते हैं तो यह बहुत बेहतर है। सफ़ेद-स्थान सुरक्षित, वर्तमान निर्देशिका में फ़ाइलों के लिए:

for i in *.txt; do # Whitespace-safe but not recursive.
    process "$i"
done

globstarविकल्प को सक्षम करके , आप इस निर्देशिका और सभी उपनिर्देशिकाओं में सभी मेल खाने वाली फ़ाइलों को ग्लोब कर सकते हैं:

# Make sure globstar is enabled
shopt -s globstar
for i in **/*.txt; do # Whitespace-safe and recursive
    process "$i"
done

कुछ मामलों में, उदाहरण के लिए यदि फ़ाइल नाम पहले से ही एक फ़ाइल में हैं, तो आपको उपयोग करने की आवश्यकता हो सकती है read:

# IFS= makes sure it doesn't trim leading and trailing whitespace
# -r prevents interpretation of \ escapes.
while IFS= read -r line; do # Whitespace-safe EXCEPT newlines
    process "$line"
done < filename

readfindउचित रूप से सीमांकक की स्थापना के साथ संयोजन में सुरक्षित रूप से इस्तेमाल किया जा सकता है:

find . -name '*.txt' -print0 | 
    while IFS= read -r -d '' line; do 
        process "$line"
    done

अधिक जटिल खोजों के लिए, आप संभवतः findइसका -execविकल्प या इसके साथ उपयोग करना चाहेंगे -print0 | xargs -0:

# execute `process` once for each file
find . -name \*.txt -exec process {} \;

# execute `process` once with all the files as arguments*:
find . -name \*.txt -exec process {} +

# using xargs*
find . -name \*.txt -print0 | xargs -0 process

# using xargs with arguments after each filename (implies one run per filename)
find . -name \*.txt -print0 | xargs -0 -I{} process {} argument

findभी कर सकते हैं प्रत्येक फ़ाइल की निर्देशिका में सीडी का उपयोग करके एक कमांड चलाने से पहले -execdirके बजाय -exec, और इंटरैक्टिव बनाया जा सकता है (प्रत्येक फ़ाइल के लिए आदेश चलाने से पहले शीघ्र) का उपयोग कर -okके बजाय -exec(या -okdirके बजाय -execdir)।

*: तकनीकी रूप से, दोनों findऔर xargs(डिफ़ॉल्ट रूप से) कमांड को उतने ही तर्कों के साथ चलाएंगे, जितना वे कमांड लाइन पर फिट हो सकते हैं, जितनी बार सभी फाइलों के माध्यम से प्राप्त करने में लगता है। व्यवहार में, जब तक कि आपके पास बहुत बड़ी संख्या में फाइलें नहीं होंगी, और यदि आप लंबाई को पार करते हैं, लेकिन एक ही कमांड लाइन पर उन सभी की आवश्यकता होती है, तो आप SOL का एक अलग तरीका खोज लेंगे


4
यह ध्यान देने योग्य है कि done < filenameपाइप के साथ और निम्न में से एक स्टड का उपयोग किसी भी अधिक नहीं किया जा सकता है (→ लूप के अंदर कोई और अधिक संवादात्मक सामान) नहीं है, लेकिन उन मामलों में जहां इसकी आवश्यकता है एक के 3<बजाय <और जोड़ सकते हैं <&3या जोड़ सकते -u3हैं readहिस्सा है, मूल रूप से एक अलग फाइल वर्णनकर्ता का उपयोग कर। इसके अलावा, मेरा मानना read -d ''है कि जैसा है, read -d $'\0'लेकिन मैं अभी उस पर कोई आधिकारिक दस्तावेज नहीं पा सकता हूं।
phk

1
i में * .txt के लिए; कोई काम नहीं करता है, अगर कोई फाइल मेल नहीं खाती। एक एक्स्ट्रा टेस्ट जैसे [[-ई $ i] की जरूरत है
माइकल ब्रूक्स

2
मैं इस हिस्से के साथ खो गया हूं: -exec process {} \;और मेरा अनुमान है कि यह एक पूरी तरह से दूसरा सवाल है - इसका क्या मतलब है और मैं इसे कैसे जोड़ सकता हूं? जहां एक अच्छा क्यू / ए या डॉक्टर है। इस पर?
एलेक्स हॉल

1
@AlexHall आप हमेशा मैन पेज ( man find) देख सकते हैं। इस मामले में, निम्नलिखित कमांड को निष्पादित करने के लिए -execकहता findहै, जिसे ;(या +) द्वारा समाप्त किया जाता है , जिसमें {}इसे उस फ़ाइल के नाम से बदल दिया जाएगा जिसे यह प्रसंस्करण कर रहा है (या, यदि +उपयोग किया जाता है, तो सभी फाइलें जो उस स्थिति में बनाई गई हैं)।
केविन

3
@phk -d ''से बेहतर है -d $'\0'। उत्तरार्द्ध न केवल लंबा है, बल्कि यह भी सुझाव देता है कि आप अशक्त बाइट्स वाले तर्क पारित कर सकते हैं, लेकिन आप नहीं कर सकते। पहला नल बाइट स्ट्रिंग के अंत को चिह्नित करता है। बैश में $'a\0bc'रूप में ही है aऔर $'\0'रूप में ही है $'\0abc'या सिर्फ खाली स्ट्रिंग ''help readबताता है कि " डेलिम के पहले चरित्र का उपयोग इनपुट को समाप्त करने के लिए किया जाता है " इसलिए ''एक सीमांकक के रूप में उपयोग करना थोड़ा हैक है। खाली स्ट्रिंग में पहला वर्ण नल बाइट है जो हमेशा स्ट्रिंग के अंत को चिह्नित करता है (भले ही आप स्पष्ट रूप से इसे नीचे नहीं लिखते हैं)।
सोकोवई

114

आप कभी क्या करते हैं, एक forलूप का उपयोग न करें :

# Don't do this
for file in $(find . -name "*.txt")
do
    code using "$file"
done

तीन कारण:

  • लूप के लिए भी शुरू करने के लिए, findपूरा करने के लिए चलना चाहिए।
  • यदि किसी फ़ाइल नाम में कोई व्हाट्सएप (स्पेस, टैब या न्यूलाइन सहित) है, तो इसे दो अलग-अलग नामों के रूप में माना जाएगा।
  • हालांकि अब संभावना नहीं है, आप अपनी कमांड लाइन बफर से आगे निकल सकते हैं। कल्पना करें कि यदि आपकी कमांड लाइन बफर में 32KB है, और आपका forलूप 40KB का रिटर्न देता है। वह आखिरी 8KB आपके forपाश से ठीक दूर होगा और आपको यह कभी पता नहीं चलेगा।

हमेशा एक while readनिर्माण का उपयोग करें :

find . -name "*.txt" -print0 | while read -d $'\0' file
do
    code using "$file"
done

लूप निष्पादित करेगा जबकि findकमांड निष्पादित कर रहा है। साथ ही, यह कमांड तब भी काम करेगा, जब इसमें व्हॉट्सएप के साथ फाइल का नाम दिया गया हो। और, आप अपनी कमांड लाइन बफर को ओवरफ्लो नहीं करेंगे।

-print0एक फाइल विभाजक के बजाय एक नई पंक्ति के रूप में शून्य का उपयोग करेगा और -d $'\0'जबकि पढ़ने विभाजक के रूप में शून्य का प्रयोग करेंगे।


3
यह फ़ाइल नाम में नई सुर्खियों के साथ काम नहीं करेगा। -execइसके बजाय खोजने का उपयोग करें ।
उपयोगकर्ता अज्ञात

2
@userunknown - आप इसके बारे में सही हैं। -execयह सबसे सुरक्षित है क्योंकि यह शेल का उपयोग बिल्कुल नहीं करता है। हालाँकि, फ़ाइल नामों में NL काफी दुर्लभ है। फ़ाइल नामों में रिक्तियाँ काफी सामान्य हैं। मुख्य बिंदु एक forलूप का उपयोग नहीं करना है जिसे कई पोस्टर ने अनुशंसित किया था।
डेविड डब्ल्यू।

1
@userunknown - यहाँ। मैंने इसे ठीक कर लिया है, इसलिए यह अब नई लाइनों, टैब और किसी भी अन्य सफेद स्थान के साथ फ़ाइलों का ध्यान रखेगा। पोस्ट का पूरा बिंदु ओपी for file $(find)को उस से जुड़ी समस्याओं के कारण उपयोग नहीं करने के लिए कहना है।
डेविड डब्ल्यू।

4
यदि आप इसका उपयोग कर सकते हैं-यह बेहतर है, लेकिन ऐसे समय होते हैं जब आपको वास्तव में शेल को वापस दिए गए नाम की आवश्यकता होती है। उदाहरण के लिए यदि आप फ़ाइल एक्सटेंशन निकालना चाहते हैं।
बेन रेजर

5
आपको -rविकल्प का उपयोग करना चाहिए read: -r raw input - disables interpretion of backslash escapes and line-continuation in the read data
दैरा हॉपवुड

102
find . -name "*.txt"|while read fname; do
  echo "$fname"
done

नोट: यह विधि और (दूसरी) बमरगली द्वारा दर्शाई गई विधि फ़ाइल / फ़ोल्डर नामों में सफेद स्थान के साथ उपयोग करने के लिए सुरक्षित है।

आदेश में - कुछ हद तक विदेशी - फाइल / फ़ोल्डर नामों में नई सुर्खियों का मामला, आपको इस तरह के -execविधेय का सहारा लेना होगा find:

find . -name '*.txt' -exec echo "{}" \;

{}मिली आइटम के लिए प्लेसहोल्डर है और \;समाप्त करने के लिए प्रयोग किया जाता है -execविधेय।

और पूर्णता के लिए मुझे एक और प्रकार जोड़ने की जरूरत है - आप उनकी बहुमुखी प्रतिभा के लिए * निक्स तरीके से प्यार करेंगे:

find . -name '*.txt' -print0|xargs -0 -n 1 echo

यह मुद्रित आइटम को एक ऐसे \0चरित्र के साथ अलग कर देगा जिसे फ़ाइल सिस्टम या फ़ाइल नाम में किसी भी फाइल सिस्टम में मेरी जानकारी के लिए अनुमति नहीं है, और इसलिए सभी आधारों को कवर करना चाहिए। xargsएक के बाद एक उन्हें उठाता है ...


3
फ़ाइल नाम में newline यदि विफल रहता है।
उपयोगकर्ता अज्ञात

2
@user अज्ञात: आप सही हैं, यह एक ऐसा मामला है जिस पर मैंने बिल्कुल विचार नहीं किया था और मुझे लगता है कि यह बहुत ही विचित्र है। लेकिन मैंने अपने उत्तर को उसी के अनुसार समायोजित किया।
0xC0000022L

5
शायद लायक उनका कहना है कि find -print0और xargs -0दोनों जीएनयू एक्सटेंशन और पोर्टेबल नहीं (इसे POSIX) तर्क हैं। अविश्वसनीय रूप से उन प्रणालियों पर उपयोगी है जो उनके पास हैं, हालांकि!
टोबी स्पाइट

1
यह भी फ़ाइल नाम के साथ विफल रहता है जिसमें बैकस्लैश (जो read -rठीक होता है), या फ़ाइल नाम व्हाट्सएप (जो IFS= readठीक होगा) में समाप्त होता है। इसलिए BashFAQ # 1 सुझावwhile IFS= read -r filename; do ...
चार्ल्स डफी

1
इसके साथ एक और समस्या यह है कि ऐसा लगता है कि लूप का शरीर एक ही शेल में निष्पादित हो रहा है, लेकिन ऐसा नहीं है, इसलिए उदाहरण के लिए exitयह अपेक्षित नहीं होगा और लूप बॉडी में स्थापित चर लूप के बाद उपलब्ध नहीं होंगे।
EM0

17

फ़ाइल नाम में स्थान शामिल हो सकते हैं और यहां तक ​​कि वर्ण भी नियंत्रित हो सकते हैं। बैश में शेल विस्तार के लिए रिक्त स्थान (डिफ़ॉल्ट) सीमांकक हैं और इसके परिणामस्वरूप x=$(find . -name "*.txt")प्रश्न से बिल्कुल भी अनुशंसित नहीं है। यदि "the file.txt"आपको रिक्त स्थान के साथ फ़ाइल नाम मिलता है जैसे कि आपको प्रोसेसिंग के लिए 2 अलग-अलग तार मिलेंगे, यदि आप xलूप में प्रक्रिया करते हैं । आप इसे बदल सकते हैं IFSजैसे कि सीमांकक (बैश चर) को बदलकर \r\n, लेकिन फ़ाइल नाम में नियंत्रण वर्ण शामिल हो सकते हैं - इसलिए यह पूरी तरह से सुरक्षित तरीका नहीं है।

मेरे दृष्टिकोण से, प्रसंस्करण फ़ाइलों के लिए 2 अनुशंसित (और सुरक्षित) पैटर्न हैं:

1. पाश और फ़ाइल नाम विस्तार के लिए उपयोग करें:

for file in ./*.txt; do
    [[ ! -e $file ]] && continue  # continue, if file does not exist
    # single filename is in $file
    echo "$file"
    # your code here
done

2. खोज-पढ़ें-जबकि और प्रक्रिया प्रतिस्थापन का उपयोग करें

while IFS= read -r -d '' file; do
    # single filename is in $file
    echo "$file"
    # your code here
done < <(find . -name "*.txt" -print0)

टिप्पणियों

पैटर्न 1 पर:

  1. यदि कोई मिलान फ़ाइल नहीं मिली है, तो bash सर्च पैटर्न ("* .txt") लौटाता है - इसलिए अतिरिक्त लाइन "जारी रहती है, यदि फ़ाइल मौजूद नहीं है" की आवश्यकता है। देख बैश मैनुअल, फ़ाइल नाम विस्तार
  2. nullglobइस अतिरिक्त रेखा से बचने के लिए शेल विकल्प का उपयोग किया जा सकता है।
  3. "यदि failglobशेल विकल्प सेट है, और कोई मिलान नहीं मिला है, तो एक त्रुटि संदेश मुद्रित होता है और कमांड निष्पादित नहीं होता है।" (ऊपर बैश मैनुअल से)
  4. शेल विकल्प globstar: "यदि सेट किया जाता है, तो फ़ाइल नाम विस्तार के संदर्भ में उपयोग किया जाने वाला पैटर्न '**' सभी फ़ाइलों और शून्य या अधिक निर्देशिकाओं और उपनिर्देशिकाओं से मेल खाएगा। यदि पैटर्न '/' द्वारा अनुसरण किया जाता है, तो केवल निर्देशिकाएं और उपनिर्देशिकाएं मेल खाती हैं।" बैश मैनुअल, शॉप्ट बिलिन देखें
  5. फ़ाइल नाम विस्तार के लिए अन्य विकल्प: extglob, nocaseglob, dotglobऔर खोल चरGLOBIGNORE

पैटर्न 2 पर:

  1. फ़ाइल नाम रिक्त स्थान, टैब, रिक्त स्थान, नई पंक्तियां शामिल कर सकते हैं, ... एक सुरक्षित तरीका में प्रक्रिया फ़ाइल नाम के लिए, findके साथ -print0प्रयोग किया जाता है: फ़ाइल नाम सभी नियंत्रण पात्रों के साथ NUL के साथ समाप्त छपा है और। यह भी देखना ग्नू Findutils मैनपेज, असुरक्षित फ़ाइल नाम हैंडलिंग , सुरक्षित फ़ाइल नाम हैंडलिंग , फ़ाइल नाम में असामान्य वर्ण । इस विषय पर विस्तृत चर्चा के लिए नीचे डेविड ए व्हीलर देखें।

  2. कुछ लूप में परिणाम खोजने की प्रक्रिया के लिए कुछ संभावित पैटर्न हैं। अन्य (केविन, डेविड डब्ल्यू।) ने दिखाया है कि पाइप का उपयोग करके यह कैसे करें:

    files_found=1 find . -name "*.txt" -print0 | while IFS= read -r -d '' file; do # single filename in $file echo "$file" files_found=0 # not working example # your code here done [[ $files_found -eq 0 ]] && echo "files found" || echo "no files found"
    जब आप इस कोड के टुकड़े को आज़माते हैं, तो आप देखेंगे कि यह काम नहीं करता है: files_foundहमेशा "सत्य" होता है और कोड हमेशा "कोई फ़ाइल नहीं मिली" प्रतिध्वनित करेगा। कारण है: एक पाइप लाइन के प्रत्येक कमांड को एक अलग सबशेल में निष्पादित किया जाता है, इसलिए लूप के अंदर परिवर्तित चर (अलग सबस्लेम) मुख्य शेल स्क्रिप्ट में वेरिएबल को नहीं बदलता है। यही कारण है कि मैं प्रक्रिया प्रतिस्थापन को "बेहतर", अधिक उपयोगी, अधिक सामान्य पैटर्न के रूप में उपयोग करने की सलाह देता हूं।
    देखें कि मैं एक पाइप लाइन में चर सेट करता हूं। वे क्यों गायब हो जाते हैं ... (ग्रेग बैश एफएक्यू से) इस विषय पर विस्तृत चर्चा के लिए।

अतिरिक्त संदर्भ और स्रोत:


8

(@ सोसाइटी की एग्जीक्यूशन स्पीड में सुधार को शामिल करने के लिए अपडेट किया गया)

किसी के साथ $SHELLजो इसका समर्थन करता है (डैश / zsh / bash ...):

find . -name "*.txt" -exec $SHELL -c '
    for i in "$@" ; do
        echo "$i"
    done
' {} +

किया हुआ।


मूल उत्तर (छोटा, लेकिन धीमा):

find . -name "*.txt" -exec $SHELL -c '
    echo "$0"
' {} \;

1
गुड़ के रूप में धीमा (क्योंकि यह प्रत्येक फ़ाइल के लिए एक शेल लॉन्च करता है) लेकिन यह काम करता है। +1
डग

1
इसके बजाय \;आप +एकल के लिए अधिक से अधिक फ़ाइलों को पास करने के लिए उपयोग कर सकते हैं exec। फिर "$@"इन सभी मापदंडों को संसाधित करने के लिए शेल स्क्रिप्ट के अंदर का उपयोग करें ।
सोकोवई

3
इस कोड में एक बग है। लूप को पहला परिणाम याद आ रहा है। ऐसा इसलिए $@है क्योंकि यह आम तौर पर स्क्रिप्ट का नाम है क्योंकि इसे छोड़ देता है। हमें केवल dummyबीच में जोड़ने की जरूरत है 'और {}इसलिए यह स्क्रिप्ट नाम की जगह ले सकता है, यह सुनिश्चित करता है कि सभी मैचों को लूप द्वारा संसाधित किया जाए।
BCartolo

क्या होगा अगर मुझे नए बनाए गए शेल के बाहर से अन्य चर की आवश्यकता है?
Jodo

OTHERVAR=foo find . -na.....आपको $OTHERVARउस नए बनाए गए शेल के भीतर से एक्सेस करने की अनुमति देनी चाहिए ।
user569825

6
# Doesn't handle whitespace
for x in `find . -name "*.txt" -print`; do
  process_one $x
done

or

# Handles whitespace and newlines
find . -name "*.txt" -print0 | xargs -0 -n 1 process_one

3
for x in $(find ...)इसमें व्हॉट्सएप के साथ किसी भी नाम के लिए टूट जाएगा। के साथ एक ही find ... | xargsहै जब तक आप का उपयोग -print0और-0
ग्लेन जैकमैन

1
find . -name "*.txt -exec process_one {} ";"इसके बजाय उपयोग करें । परिणाम एकत्रित करने के लिए हमें xargs का उपयोग क्यों करना चाहिए, हमारे पास पहले से ही है?
उपयोगकर्ता अज्ञात

@userunknown खैर यह सब निर्भर करता है कि क्या process_oneहै। यदि यह एक वास्तविक कमांड के लिए प्लेसहोल्डर है , तो सुनिश्चित करें कि यह काम करेगा (यदि आप टाइपो को ठीक करते हैं और बाद में क्लोजिंग उद्धरण जोड़ते हैं "*.txt)। लेकिन अगर process_oneकोई उपयोगकर्ता-परिभाषित फ़ंक्शन है, तो आपका कोड काम नहीं करेगा।
टॉक्सालॉट

@toxalot: हाँ, लेकिन कॉल करने के लिए स्क्रिप्ट में फ़ंक्शन लिखने के लिए यह एक समस्या नहीं होगी।
यूजर अनजान

4

findयदि आप बाद में आउटपुट का उपयोग करना चाहते हैं तो आप अपने आउटपुट को एरे में स्टोर कर सकते हैं :

array=($(find . -name "*.txt"))

अब प्रत्येक तत्व को नई पंक्ति में प्रिंट करने के लिए, आप या तो forऐरे के सभी तत्वों के लिए लूप इट्रेटिंग का उपयोग कर सकते हैं, या आप प्रिंटफ स्टेटमेंट का उपयोग कर सकते हैं।

for i in ${array[@]};do echo $i; done

या

printf '%s\n' "${array[@]}"

आप भी उपयोग कर सकते हैं:

for file in "`find . -name "*.txt"`"; do echo "$file"; done

यह प्रत्येक फ़ाइल नाम को newline में प्रिंट करेगा

findआउटपुट को केवल सूची रूप में मुद्रित करने के लिए, आप निम्न में से किसी एक का उपयोग कर सकते हैं:

find . -name "*.txt" -print 2>/dev/null

या

find . -name "*.txt" -print | grep -v 'Permission denied'

यह त्रुटि संदेशों को हटा देगा और केवल फ़ाइल नाम को नई पंक्ति में आउटपुट के रूप में देगा।

यदि आप फ़ाइल नाम के साथ कुछ करना चाहते हैं, तो इसे सरणी में संग्रहीत करना अच्छा है, अन्यथा उस स्थान का उपभोग करने की कोई आवश्यकता नहीं है और आप सीधे आउटपुट से प्रिंट कर सकते हैं find


1
फ़ाइल नामों में रिक्त स्थान के साथ सरणी पर लूपिंग विफल हो जाता है।
EM0

आपको यह उत्तर हटा देना चाहिए। यह फ़ाइल नाम या निर्देशिका नामों में रिक्त स्थान के साथ काम नहीं करता है।
jww

4

यदि आप मान सकते हैं कि फ़ाइल के नाम में नई सीमाएँ नहीं हैं, तो आप findनिम्नलिखित कमांड का उपयोग करके बाश सरणी में आउटपुट पढ़ सकते हैं :

readarray -t x < <(find . -name '*.txt')

ध्यान दें:

  • -treadarrayन्यूलाइन्स छीनने का कारण बनता है।
  • यह काम नहीं करेगा अगर readarrayएक पाइप में है, इसलिए प्रक्रिया प्रतिस्थापन।
  • readarray बैश 4 के बाद से उपलब्ध है।

4.4 बैश और ऊपर भी -dसीमांकक निर्दिष्ट करने के लिए पैरामीटर का समर्थन करता है। नई नाम के बजाय अशक्त वर्ण का उपयोग करते हुए, फ़ाइल नामों को परिसीमन करने के लिए भी दुर्लभ मामले में फ़ाइल नाम में नई सीमाएँ हैं:

readarray -d '' x < <(find . -name '*.txt' -print0)

readarrayभी mapfileएक ही विकल्प के साथ लागू किया जा सकता है ।

संदर्भ: https://mywiki.wooledge.org/BashFAQ/005#Loading_lines_from_a_file_or_stream


यह सबसे अच्छा जवाब है! के साथ काम करता है: * फ़ाइल नाम में रिक्त स्थान * कोई मेल नहीं फ़ाइलें * exitजब परिणामों पर पाशन
EM0

सभी के साथ काम नहीं करता है संभव फ़ाइल नाम के , हालांकि - उसके लिए, आपको उपयोग करना चाहिएreadarray -d '' x < <(find . -name '*.txt' -print0)
चार्ल्स डफी

3

मैं वैसा उपयोग करना पसंद करता हूं जो पहले चर को सौंपा गया है और IFS अनुसरण के रूप में नई लाइन पर स्विच किया गया है:

FilesFound=$(find . -name "*.txt")

IFSbkp="$IFS"
IFS=$'\n'
counter=1;
for file in $FilesFound; do
    echo "${counter}: ${file}"
    let counter++;
done
IFS="$IFSbkp"

बस उसी स्थिति में जब आप DATA के एक ही सेट पर अधिक कार्य करना चाहते हैं और आपके सर्वर पर बहुत धीमा है (I / 0 उपयोग उपयोगिता)


2

आप findइस तरह से एक सरणी में लौटे फ़ाइल नाम रख सकते हैं :

array=()
while IFS=  read -r -d ''; do
    array+=("$REPLY")
done < <(find . -name '*.txt' -print0)

अब आप अलग-अलग वस्तुओं को एक्सेस करने के लिए सरणी के माध्यम से बस लूप कर सकते हैं और जो कुछ भी आप चाहते हैं उनके साथ कर सकते हैं।

नोट: यह सफेद स्थान सुरक्षित है।


1
4.4 या अधिक बैश के साथ आप लूप के बजाय सिंगल कमांड का उपयोग कर सकते हैं mapfile -t -d '' array < <(find ...):। के लिए सेटिंग IFSआवश्यक नहीं है mapfile
सोकोवई

1

@ एफके के अन्य उत्तरों और टिप्पणी के आधार पर, fd # 3 का उपयोग करना:
(जो अभी भी लूप के अंदर स्टड का उपयोग करने की अनुमति देता है)

while IFS= read -r f <&3; do
    echo "$f"

done 3< <(find . -iname "*filename*")

-1

find <path> -xdev -type f -name *.txt -exec ls -l {} \;

यह फाइलों को सूचीबद्ध करेगा और विशेषताओं के बारे में विवरण देगा।


-5

अगर आप खोजने के बजाय grep का उपयोग करते हैं तो कैसा रहेगा?

ls | grep .txt$ > out.txt

अब आप इस फ़ाइल को पढ़ सकते हैं और फ़ाइलनाम सूची के रूप में हैं।


6
नहीं, यह मत करो। आपको ls के आउटपुट को पार्स क्यों नहीं करना चाहिए । यह नाजुक है, बहुत नाजुक है।
फेडोरक्वी 'एसओ ने'
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.