কীভাবে ফাইলের নামগুলি সন্ধান করে ফিরে আসবে?


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

যদি আমি বাশ শেলটিতে উপরের কোডের টুকরোটি চালাই তবে আমি যা পাই তা হ'ল একটি স্ট্রিং যা বেশ কয়েকটি ফাইলের নাম ফাঁকা দ্বারা পৃথক করা থাকে, তালিকা নয়।

অবশ্যই, আমি তালিকা পেতে তাদের আরও ফাঁকা করে আলাদা করতে পারি, তবে আমি নিশ্চিত যে এটি করার আরও ভাল উপায় আছে।

সুতরাং কোন findআদেশের ফলাফলের মধ্য দিয়ে লুপ করার সর্বোত্তম উপায় কী?


3
ফাইলের নাম লুপ করার সর্বোত্তম উপায়টি আপনি আসলে এটির সাথে কী করতে চান তার উপর কিছুটা নির্ভর করে, তবে আপনি যদি কোনও ফাইলের নামে কোনও সাদা জায়গার গ্যারান্টি না দিতে পারেন তবে এটি করার দুর্দান্ত উপায় এটি নয়। সুতরাং আপনি ফাইল লুপিং মধ্যে কি করতে চান?
কেভিন

1
অনুগ্রহ সম্পর্কে : এখানে মূল ধারণাটি হ'ল একটি প্রমিত উত্তর পাওয়া যা সম্ভাব্য সমস্ত কেস (নতুন লাইনযুক্ত ফাইলের নাম, সমস্যাযুক্ত চরিত্রগুলি ...) কভার করে। এরপরে ধারণাটি হ'ল কিছু ফাইল করার জন্য এই ফাইলের নামগুলি ব্যবহার করা (অন্য কমান্ড কল করুন, কিছু নাম পরিবর্তন করুন ...)। ধন্যবাদ!
ফেডরকিই 'এসও ক্ষতিগ্রস্থ হওয়া বন্ধ করুন'

ভুলে যাবেন না যে কোনও ফাইল বা ফোল্ডারের নামটিতে ".txt" এর পরে স্থান এবং অন্য স্ট্রিং থাকতে পারে, উদাহরণস্বরূপ "কিছু।
টেক্সট

অ্যারে ব্যবহার করুন, ভের নয়, তবে x=( $(find . -name "*.txt") ); echo "${x[@]}"আপনি লুপ করতে পারবেনfor item in "${x[@]}"; { echo "$item"; }
ইভান

উত্তর:


389

টিএল; ডিআর: আপনি যদি খুব সঠিক উত্তরের জন্য এখানে থাকেন তবে আপনি সম্ভবত আমার ব্যক্তিগত পছন্দ চান, 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

এটা অনেক ভাল উল্লিখিত glob যখন আপনি করতে পারেন। বর্তমান ডিরেক্টরিতে ফাইলের জন্য সাদা-স্থান নিরাপদ:

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(ডিফল্টরূপে) কমান্ডটি যতটা আর্গুমেন্টের সাথে কমান্ড লাইনে ফিট করতে পারে ততবার চালাবে, যতবার সমস্ত ফাইলের মধ্যে এটি লাগে। অনুশীলনে, আপনার যদি খুব বড় সংখ্যক ফাইল না থাকে তবে তা বিবেচনাধীন নয় এবং যদি আপনি দৈর্ঘ্য অতিক্রম করে থাকেন তবে সেগুলি একই কমান্ড লাইনে প্রয়োজন হয়, আপনি অন্যরকম উপায় খুঁজে পাবেন।


4
এটি লক্ষণীয় যে done < filename, পাইপের ক্ষেত্রে এবং নিম্নলিখিতটি পাইপের সাথে স্টিডিনকে আর ব্যবহার করা যাবে না (লুপের অভ্যন্তরে আর ইন্টারেক্টিভ স্টাফ নেই), তবে যেখানে প্রয়োজন তার 3<পরিবর্তে এটি ব্যবহার করতে <এবং যুক্ত করতে <&3বা যুক্ত -u3করতে পারেন readঅংশ, মূলত একটি পৃথক ফাইল বর্ণনাকারী ব্যবহার করে। এছাড়াও, আমি বিশ্বাস করি read -d ''এটি একই রকম read -d $'\0'তবে আমি এখনই কোনও অফিসিয়াল ডকুমেন্টেশন পাই না।
পিএইচকে

1
আমার জন্য * .txt; কোনও ফাইলের সাথে মেলে না, কাজ করে না। একটি অক্স্ট্রা পরীক্ষা যেমন [[-e $ i]] প্রয়োজন
মাইকেল ব্রুকস

2
আমি এই অংশটি দিয়ে হারিয়েছি: -exec process {} \;এবং আমার ধারণা এটি সম্পূর্ণ অন্য প্রশ্ন - এর অর্থ কী এবং আমি কীভাবে এটি ব্যবহার করব? কোথায় ভাল প্রশ্ন / এ বা ডক। চালু কর?
অ্যালেক্স হল

1
@ অ্যালেক্সহল আপনি সর্বদা ম্যান পেজগুলিতে ( man find) দেখতে পারেন। এই ক্ষেত্রে, (বা ) দ্বারা সমাপ্ত, নিম্নলিখিত কমান্ডটি কার্যকর করতে -execবলে , যেখানে এটি প্রক্রিয়া করা ফাইলটির নাম দ্বারা প্রতিস্থাপন করা হবে (বা যদি এটি ব্যবহৃত হয়, সমস্ত ফাইল যা এই অবস্থাতে পরিণত করেছে)। find;+{}+
কেভিন

3
@ পিএফকে এর -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একটি ফাইল বিভাজক পরিবর্তে একটি newline যেমন শূন্য ব্যবহার করবে এবং -d $'\0'যখন পড়া বিভাজক হিসেবে শূন্য ব্যবহার করবে।


3
এটি ফাইলের নামগুলিতে নতুন লাইনের সাথে কাজ করবে না। -execপরিবর্তে সন্ধানের ব্যবহার করুন ।
ব্যবহারকারী অজানা

2
@ ব্যবহারকারী-অজ্ঞাত - আপনি এ সম্পর্কে ঠিক বলেছেন। -execএটি সবচেয়ে নিরাপদ যেহেতু এটি শেলটি একেবারেই ব্যবহার করে না। তবে ফাইলের নামে এনএল বেশ বিরল। ফাইলের নামের জায়গাগুলি বেশ সাধারণ। মূল বিষয়টি হ'ল forলুপটি ব্যবহার না করা যা বহু পোস্টার সুপারিশ করেছেন।
ডেভিড ডব্লিউ।

1
@ ব্যবহারকারী-অজ্ঞাত - এখানে। আমি এটি স্থির করেছি, সুতরাং এটি এখন নতুন লাইন, ট্যাব এবং অন্য কোনও সাদা স্থানের ফাইলগুলির যত্ন নেবে। পোস্টটির পুরো বিষয়টি হ'ল ওপিকে এর 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

দ্রষ্টব্য: bmargulies দ্বারা দেখানো এই পদ্ধতি এবং (দ্বিতীয়) পদ্ধতি ফাইল / ফোল্ডারের নামগুলিতে সাদা স্থান সহ নিরাপদ।

ফাইল / ফোল্ডারের নামগুলিতে নতুন লাইনের ক্ষেত্রে - কিছুটা বহিরাগত - এছাড়াও রাখতে, আপনাকে -execএর findমতো প্রিকিকেট অবলম্বন করতে হবে :

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

এটি {}হ'ল পাওয়া আইটেমের স্থানধারক এবং ভবিষ্যদ্বাণীটি \;শেষ করতে ব্যবহৃত হয় -exec

এবং সম্পূর্ণতার জন্য আমাকে অন্য রূপটি যুক্ত করতে দিন - আপনি তাদের বহুমুখিতাটির জন্য * নিক্স উপায়গুলি পছন্দ করবেন:

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

এটি মুদ্রিত আইটেমগুলিকে এমন একটি \0অক্ষর দিয়ে আলাদা করবে যা ফাইল বা ফোল্ডারের নামগুলির কোনও ফাইল সিস্টেমে মঞ্জুরিপ্রাপ্ত নয়, আমার জ্ঞানের জন্য এবং তাই সমস্ত ঘাঁটি আবরণ করা উচিত। xargsএকের পর এক তাদের তুলে ধরে ...


3
ফাইলনেলে নতুন লাইন ব্যর্থ হয়।
ব্যবহারকারী অজানা

2
@ ব্যবহারকারী অজানা: আপনি ঠিক বলেছেন, এটি এমন একটি ঘটনা যা আমি মোটেও বিবেচনা করি নি এবং এটি আমার কাছে মনে হয় খুব বহিরাগত। তবে আমি সেই অনুযায়ী আমার উত্তরটি সামঞ্জস্য করেছি।
0xC0000022L

5
সম্ভবত এটি উল্লেখ করার মতো find -print0এবং xargs -0এটি উভয়ই GNU এক্সটেনশান এবং পোর্টেবল (POSIX) যুক্তি নয়। যদিও সেই সিস্টেমে রয়েছে তাদের জন্য অবিশ্বাস্যভাবে কার্যকর!
টবি স্পিড 15

1
এটি ব্যাকস্ল্যাশযুক্ত ফাইলের নামগুলি (যা read -rঠিক করবে), অথবা সাদা নামক স্থানে থাকা ফাইলের নামগুলি (যা ঠিক করবে) এর সাথে ব্যর্থ হয় IFS= read। অতএব বাশফাক # 1 পরামর্শ দিচ্ছেwhile IFS= read -r filename; do ...
চার্লস ডাফি

1
এর সাথে আর একটি সমস্যা হ'ল মনে হচ্ছে লুপটির বডি একই শেলের মধ্যে চালিত হচ্ছে, তবে এটি তা নয়, উদাহরণস্বরূপ exitপ্রত্যাশার মতো কাজ করবে না এবং লুপের বর্ধিত ভেরিয়েবলগুলি লুপের পরে উপলব্ধ হবে না।
EM0

17

ফাইলের নামগুলিতে স্পেস এবং এমনকি নিয়ন্ত্রণের অক্ষর অন্তর্ভুক্ত থাকতে পারে। ব্যাশে শেল প্রসারণের জন্য স্পেসগুলি (ডিফল্ট) ডিলিমিটার হয় এবং এর ফলে x=$(find . -name "*.txt")প্রশ্ন থেকে মোটেও প্রস্তাব দেওয়া হয় না। যদি ফাঁকা জায়গাগুলির সাথে ফাইলের নাম পাওয়া যায় যেমন "the file.txt"আপনি xকোনও লুপে প্রক্রিয়াজাত করেন তবে প্রসেসিংয়ের জন্য 2 টি পৃথক স্ট্রিং পাবেন । আপনি ডিলিমিটার (ব্যাশ 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

২) সন্ধানের সময় পড়ুন এবং বিকল্প প্রতিস্থাপন করুন

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

মন্তব্য

প্যাটার্ন 1 এ:

  1. বাশ অনুসন্ধানের প্যাটার্নটি ("* .txt") ফিরিয়ে দেয় যদি কোনও মিল খুঁজে পাওয়া যায় না এমন ফাইল - সুতরাং অতিরিক্ত লাইন "চালিয়ে যান, যদি ফাইলটি বিদ্যমান না থাকে" প্রয়োজন হয়। দেখতে ব্যাশ ম্যানুয়াল, ফাইলের নাম সম্প্রসারণ
  2. nullglobএই অতিরিক্ত লাইনটি এড়াতে শেল বিকল্পটি ব্যবহার করা যেতে পারে।
  3. "যদি failglobশেল বিকল্পটি সেট করা থাকে এবং কোনও মিল খুঁজে পাওয়া যায় না, একটি ত্রুটি বার্তা মুদ্রিত হয় এবং কমান্ডটি কার্যকর হয় না" " (উপরের বাশ ম্যানুয়াল থেকে)
  4. শেল বিকল্প globstar: "যদি সেট করা থাকে তবে ফাইল নাম সম্প্রসারণ প্রসঙ্গে ব্যবহৃত প্যাটার্ন '**' সমস্ত ফাইল এবং শূন্য বা আরও বেশি ডিরেক্টরি এবং উপ-ডিরেক্টরিগুলির সাথে মিলবে। দেখতে ব্যাশ ম্যানুয়াল, Shopt Builtin
  5. ফাইলের নাম বিস্তৃতির জন্য অন্যান্য অপশন: extglob, nocaseglob, dotglob& শেল পরিবর্তনশীলGLOBIGNORE

প্যাটার্ন 2 এ:

  1. ফাইলনামগুলিতে একটি ফাঁকা, ট্যাব, ফাঁকা জায়গা, নিউলাইনস, ... ব্যবহার করা যেতে পারে, findযাতে নিরাপদ উপায়ে -print0ফাইল নাম ব্যবহার করা যায়: ফাইলের নামগুলি সমস্ত নিয়ন্ত্রণের অক্ষর দিয়ে মুদ্রিত হয় এবং NUL দিয়ে সমাপ্ত হয়। আরো দেখুন Gnu Findutils র manpage, অনিরাপদ ফাইলের নাম হ্যান্ডলিং , নিরাপদ ফাইলের নাম হ্যান্ডলিং , ফাইলের নামের অস্বাভাবিক অক্ষর । এই বিষয়ে বিস্তারিত আলোচনার জন্য নীচে ডেভিড এ হুইলারের দেখুন।

  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এটি সমর্থন করে এমন কোনও সাথে (ড্যাশ / জেডএস / বাশ ...):

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এর মধ্যে যুক্ত করা দরকার 'এবং {}এটি স্ক্রিপ্টের নামের জায়গাটি নিতে পারে, এটি নিশ্চিত করে যে সমস্ত ম্যাচ লুপ দ্বারা প্রক্রিয়া করা হয়।
বিসিআরটোলো

নতুন তৈরি শেলের বাইরে যদি আমার অন্যান্য ভেরিয়েবলের প্রয়োজন হয়?
জোডো

OTHERVAR=foo find . -na.....আপনাকে $OTHERVARনতুনভাবে তৈরি শেলের মধ্যে থেকে অ্যাক্সেস করার অনুমতি দেওয়া উচিত ।
ব্যবহারকারী569825

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 ব্যবহার করা উচিত, আমরা ইতিমধ্যে পেয়েছি?
ব্যবহারকারীর অজানা

@ ইউজারুননড ওয়েল যে সমস্ত কিসের উপর নির্ভর করে 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

এটি প্রতিটি ফাইলের নাম নতুন লাইনে মুদ্রণ করবে

কেবলমাত্র findতালিকা আকারে আউটপুট মুদ্রণ করতে, আপনি নিম্নলিখিত দুটি ব্যবহার করতে পারেন:

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

অথবা

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

এটি ত্রুটি বার্তাগুলি সরিয়ে দেবে এবং কেবলমাত্র নতুন লাইনে আউটপুট হিসাবে ফাইলের নাম দেবে।

আপনি যদি ফাইলের নাম দিয়ে কিছু করতে চান, এটি অ্যারেতে সংরক্ষণ করা ভাল, অন্যথায় সেই জায়গাটি গ্রাস করার দরকার নেই এবং আপনি সরাসরি আউটপুট মুদ্রণ করতে পারেন find


1
অ্যারের উপরে লুপিং ফাইলের ফাঁকে ফাঁকে ব্যর্থ হয়।
EM0

আপনার এই উত্তরটি মুছে ফেলা উচিত। এটি ফাইলের নাম বা ডিরেক্টরি নামের জায়গাগুলির সাথে কাজ করে না।
jwww

4

আপনি যদি ধরে নিতে পারেন যে ফাইলের নামগুলিতে নতুন লাইন নেই, তবে আপনি findনিম্নলিখিত কমান্ডটি ব্যবহার করে একটি বাশ অ্যারেতে আউটপুট পড়তে পারেন :

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

বিঃদ্রঃ:

  • -treadarrayনতুন লাইনের ফালা কারণ ।
  • readarrayপাইপে থাকলে এটি কাজ করবে না , সুতরাং প্রক্রিয়াটি প্রতিস্থাপন।
  • readarray 4-এর জন্য উপলব্ধ।

4.4 বাশ এবং আরও বেশি -dডিলিমিটার নির্দিষ্ট করার জন্য প্যারামিটারকে সমর্থন করে । ফাইলের নামগুলি সীমাবদ্ধ করতে নিউলাইন পরিবর্তে নাল অক্ষর ব্যবহার করে, ফাইলের নামগুলিতে নতুন লাইন থাকা বিরল ক্ষেত্রেও কাজ করে:

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

readarraymapfileএকই বিকল্পগুলির সাথে অনুরোধ করা যেতে পারে ।

তথ্যসূত্র: https://mywiki.wooledge.org/BashFAQ/005# লডিং_লাইনস_ফর্ম_এ_ফাইলে_আর_প্রবাহ


এটাই সেরা উত্তর! এর সাথে কাজ করে: * ফাইলের exit
নামগুলিতে

সমস্ত সম্ভাব্য ফাইলের সাথে কাজ করে না , যদিও - তার জন্য আপনার ব্যবহার করা উচিতreadarray -d '' x < <(find . -name '*.txt' -print0)
চার্লস ডফি

3

আমি প্রথমে কোনটি ভেরিয়েবলের জন্য নির্ধারিত হয় এবং আইএফএস অনুসরণ করে নতুন লাইনে স্যুইচ করে তা ব্যবহার করতে চাই:

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

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

কেবলমাত্র যদি আপনি একইভাবে ডেটার একই সেটটিতে আরও ক্রিয়া পুনরাবৃত্তি করতে চান এবং আপনার সার্ভারে খুব ধীর গতির সন্ধান করতে চান (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

অন্যান্য উত্তর এবং @ fk এর মন্তব্যের ভিত্তিতে, 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

আপনি যদি পরিবর্তে গ্রেপ ব্যবহার করেন তবে কীভাবে?

ls | grep .txt$ > out.txt

এখন আপনি এই ফাইলটি পড়তে পারেন এবং ফাইলের নামগুলি একটি তালিকা আকারে রয়েছে।


আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.