গৃহীত / উচ্চ-ভোট প্রাপ্ত উত্তরগুলি দুর্দান্ত, তবে সেগুলিতে কয়েকটি অদ্ভুত-বিব্রত বিশদের অভাব রয়েছে। শেল পাথ-নাম সম্প্রসারণ (গ্লোব) ব্যর্থ হয়, যখন ফাইলের নামগুলি এমবেড করা নিউলাইন / ড্যাশ প্রতীক ধারণ করে এবং কমান্ড আউটপুটটিকে লুপের বাইরে পুনঃনির্দেশকে সরিয়ে নিয়ে ফলাফল লেখার সময় কীভাবে পরিচালনা করতে হয় তার ক্ষেত্রে এই পোস্টটি অন্তর্ভুক্ত করে covers ফাইল।
যখন ব্যবহার শেল উল্লিখিত glob সম্প্রসারণ চলমান *
সেখানে যদি আছে সম্প্রসারণ ব্যর্থ করার জন্য একটি সম্ভাবনা আছে কোন ফাইল ডিরেক্টরি ও একটি অ-প্রসারিত উল্লিখিত glob স্ট্রিং উপস্থিত কমান্ড চালানো যাবে, যা অবাঞ্ছিত ফলাফল হতে পারে প্রেরণ করা হবে না। bash
শেল এই ব্যবহারের জন্য একটি বর্ধিত শেল বিকল্প প্রদান করে nullglob
। সুতরাং লুপটি মূলত আপনার ফাইলগুলি সম্বলিত ডিরেক্টরিতে অন্তর্ভুক্ত হয়
shopt -s nullglob
for file in ./*; do
cmdToRun [option] -- "$file"
done
এক্সপ্রেশন ./*
কোনও ফাইল ফেরত না দেয় এটি আপনাকে নিরাপদে লুপের জন্য প্রস্থান করতে দেয় (ডিরেক্টরিটি ফাঁকা থাকলে)
বা POSIX অনুবর্তী ভাবে ( nullglob
হয় bash
নির্দিষ্ট)
for file in ./*; do
[ -f "$file" ] || continue
cmdToRun [option] -- "$file"
done
এক্সপ্রেশন একবারে ব্যর্থ হয়ে যায় এবং শর্তটি [ -f "$file" ]
পরীক্ষা না করে অন-প্রসারিত স্ট্রিংটি ./*
সেই ডিরেক্টরিতে কোনও বৈধ ফাইলের নাম কিনা এটি আপনাকে লুপের ভিতরে যেতে দেয় which সুতরাং এই শর্তে ব্যর্থতা ব্যবহার করে continue
আমরা আবার লুপটিতে আবার শুরু করি for
যা পরবর্তী সময়ে চলবে না।
--
ফাইল নামের যুক্তিটি পাস করার ঠিক আগে ব্যবহারের বিষয়টিও নোট করুন । এটি প্রয়োজন কারণ পূর্বে উল্লিখিত হিসাবে, শেল ফাইলের নামগুলিতে ফাইলের যে কোনও জায়গায় ড্যাশ থাকতে পারে। শেল কমান্ডগুলির মধ্যে কিছু এটি ব্যাখ্যা করে এবং নামটি সঠিকভাবে উদ্ধৃত না করা হলে কমান্ড বিকল্প হিসাবে তাদের আচরণ করে এবং পতাকা সরবরাহ করা হয় কিনা তা ভেবে কমান্ডটি কার্যকর করে।
--
সংকেত যে ক্ষেত্রে যা অর্থ হলো কমাণ্ড লাইন অপশন সম্বন্ধে শেষ, আদেশ কমান্ড পতাকা হিসাবে এই বিন্দু অতিক্রম কিন্তু শুধুমাত্র ফাইলের নামের কোন পংক্তি সঠিকরূপে মীমাংসা করা উচিত নয়।
যখন নামগুলি গ্লোব অক্ষর বা সাদা স্পেস থাকে তখন ফাইলের নামগুলি ডাবল-কোট করা সঠিকভাবে কেসগুলি সমাধান করে। তবে * নিক্স ফাইলের নামগুলিতে সেগুলিতে নতুন লাইনও থাকতে পারে। সুতরাং আমরা ফাইলের নামগুলি কেবলমাত্র অক্ষর দিয়ে সীমিত করি যা কোনও বৈধ ফাইল নামের অংশ হতে পারে না - নাল বাইট ( \0
)। যেহেতু bash
অভ্যন্তরীণভাবে C
স্টাইলের স্ট্রিংগুলি ব্যবহার করা হয় যেখানে নাল বাইটগুলি স্ট্রিংয়ের সমাপ্তি নির্দেশ করতে ব্যবহৃত হয়, এটি এটির জন্য সঠিক প্রার্থী।
সুতরাং কমান্ডের বিকল্পটি printf
ব্যবহার করে এই নুল বাইট দিয়ে ফাইলগুলি সীমিত করতে শেলের বিকল্পটি ব্যবহার করে , আমরা নীচে করতে পারি-d
read
( shopt -s nullglob; printf '%s\0' ./* ) | while read -rd '' file; do
cmdToRun [option] -- "$file"
done
nullglob
এবং printf
প্রায় আবৃত করা হয় (..)
, যার মানে তারা মূলত একটি উপ-শেল (শিশু শেল) চালানোর কারণ এড়াতে nullglob
একবার কমান্ড প্রস্থান করে, পিতা বা মাতা শেল নিয়ে গভীরভাবে চিন্তা করার বিকল্প। -d ''
বিকল্প read
কমান্ড না POSIX অনুবর্তী, তাই একটি প্রয়োজন bash
শেল এই কাজ করা জন্য। find
কমান্ড ব্যবহার করে এটি করা যায়
while IFS= read -r -d '' file; do
cmdToRun [option] -- "$file"
done < <(find -maxdepth 1 -type f -print0)
যে find
বাস্তবায়নগুলি সমর্থন করে না -print0
(জিএনইউ এবং ফ্রিবিএসডি বাস্তবায়ন ব্যতীত), এটি ব্যবহার করে অনুকরণ করা যেতে পারেprintf
find . -maxdepth 1 -type f -exec printf '%s\0' {} \; | xargs -0 cmdToRun [option] --
আর একটি গুরুত্বপূর্ণ ফিক্স হ'ল ফাইলের I / O এর একটি উচ্চ সংখ্যা হ্রাস করার জন্য পুনরায় দিকটি লুপের বাইরে নিয়ে যাওয়া। লুপটির অভ্যন্তরে ব্যবহৃত হলে, শেলটি ফর-লুপের প্রতিটি পুনরাবৃত্তির জন্য দুবার সিস্টেম কল প্রয়োগ করতে হবে, একবার খোলার জন্য এবং একবার ফাইলের সাথে সম্পর্কিত ফাইল বিবরণকারী বন্ধ করার জন্য। এটি বড় পুনরাবৃত্তিগুলি চালানোর জন্য আপনার পারফরম্যান্সের বোতল-ঘাড়ে পরিণত হবে। প্রস্তাবিত পরামর্শ হ'ল এটিকে লুপের বাইরে নিয়ে যাওয়া।
এই সংশোধনগুলি সহ উপরের কোডটি প্রসারিত করা, আপনি করতে পারেন
( shopt -s nullglob; printf '%s\0' ./* ) | while read -rd '' file; do
cmdToRun [option] -- "$file"
done > results.out
যা মূলত আপনার ফাইলের ইনপুটটির প্রতিটি পুনরাবৃত্তির জন্য স্ট্যান্ডআউটে আপনার আদেশের বিষয়বস্তু রাখবে এবং যখন লুপটি শেষ হবে, স্ট্যাডআউটের বিষয়বস্তু লিখতে এবং সংরক্ষণ করার জন্য লক্ষ্য ফাইলটি একবার খুলুন। find
একই সমতুল্য সংস্করণ হবে
while IFS= read -r -d '' file; do
cmdToRun [option] -- "$file"
done < <(find -maxdepth 1 -type f -print0) > results.out
ls <directory> | xargs cmd [options] {filenames put in here automatically by xargs} [more arguments] > results.out