আমাকে সমস্ত উপ-ডিরেক্টরিগুলি পরিদর্শন করতে হবে এবং কতগুলি ফাইল রয়েছে (তাদের পূর্বে পুনরাবৃত্তি ছাড়াই) তা রিপোর্ট করতে হবে:
directoryName1 numberOfFiles
directoryName2 numberOfFiles
আমাকে সমস্ত উপ-ডিরেক্টরিগুলি পরিদর্শন করতে হবে এবং কতগুলি ফাইল রয়েছে (তাদের পূর্বে পুনরাবৃত্তি ছাড়াই) তা রিপোর্ট করতে হবে:
directoryName1 numberOfFiles
directoryName2 numberOfFiles
উত্তর:
এটি এটি নিরাপদ এবং পোর্টেবল উপায়ে করে। এটি অদ্ভুত ফাইলের নাম দ্বারা বিভ্রান্ত হবে না।
for f in *; do [ -d ./"$f" ] && find ./"$f" -maxdepth 1 -exec echo \; | wc -l && echo $f; done
দ্রষ্টব্য যে এটি প্রথমে ফাইলগুলির সংখ্যা মুদ্রণ করবে, তারপরে একটি পৃথক লাইনে ডিরেক্টরিটির নাম। আপনি যদি ওপি'র ফর্ম্যাটটি রাখতে চান তবে আপনার আরও ফর্ম্যাটিং প্রয়োজন, যেমন
for f in *; do [ -d ./"$f" ] && find ./"$f" -maxdepth 1 -exec echo \;|wc -l|tr '\n' ' ' && echo $f; done|awk '{print $2"\t"$1}'
আপনার যদি আগ্রহী সাবডাইরেক্টরিগুলির একটি নির্দিষ্ট সেট থাকে তবে আপনি *
সেগুলি দিয়ে প্রতিস্থাপন করতে পারেন ।
এটি নিরাপদ কেন? (এবং তাই স্ক্রিপ্ট-যোগ্য)
ফাইলের নামগুলিতে ব্যতীত অন্য কোনও অক্ষর থাকতে পারে /
। কয়েকটি অক্ষর রয়েছে যা শেল বা কমান্ড দ্বারা বিশেষভাবে চিকিত্সা করা হয়। এর মধ্যে স্পেস, নিউলাইন এবং ড্যাশ অন্তর্ভুক্ত।
for f in *
কনস্ট্রাক্ট ব্যবহার করা প্রতিটি ফাইলের নাম পাওয়ার একটি নিরাপদ উপায়, এতে যা কিছু থাকুক না কেন।
একবার আপনার ভেরিয়েবলের ফাইলের নাম হয়ে গেলে, তবুও আপনাকে এ জাতীয় জিনিস এড়াতে হবে find $f
। যদি $f
ফাইলের নাম অন্তর্ভুক্ত -test
, find
বিকল্প আপনি শুধু এটা দিলেন সম্পর্কে অভিযোগ করবে। এটি এড়ানোর উপায় ./
নামটির সামনে ব্যবহার করে ; এইভাবে এর একই অর্থ রয়েছে তবে এটি আর ড্যাশ দিয়ে শুরু হবে না।
নিউলাইন এবং স্পেসগুলিও একটি সমস্যা। যদি $f
ফাইলের নাম হিসাবে "হ্যালো, বন্ধু" থাকে তবে find ./$f
তা হয় find ./hello, buddy
। আপনি কহন করছি find
তাকান ./hello,
এবং buddy
। যদি সেগুলির অস্তিত্ব না থাকে তবে এটি অভিযোগ করবে এবং এটি কখনই সন্ধান করবে না ./hello, buddy
। এটি এড়ানো সহজ - আপনার ভেরিয়েবলের চারপাশে উদ্ধৃতি ব্যবহার করুন।
শেষ অবধি, ফাইলের নামগুলিতে নিউলাইনগুলি থাকতে পারে, সুতরাং ফাইলের নামের তালিকায় নতুন লাইনের গণনা কাজ করবে না; আপনি একটি নতুন লাইন সহ প্রতিটি ফাইলের নামের জন্য একটি অতিরিক্ত গণনা পাবেন। এটি এড়ানোর জন্য, ফাইলের তালিকায় নিউলাইনগুলি গণনা করবেন না; পরিবর্তে, নিউলাইনগুলি (বা অন্য কোনও চরিত্র) গণনা করুন যা একটি একক ফাইলকে উপস্থাপন করে। এ কারণেই find
কমান্ডটি সহজভাবে -exec echo \;
এবং নাও রয়েছে -exec echo {} \;
। আমি কেবল ফাইলগুলি টালাই করার উদ্দেশ্যে একটি নতুন লাইন মুদ্রণ করতে চাই।
-mindepth 1
-printf '\n'
পরিবর্তে ব্যবহার করতে পারে -exec echo
।
-printf
তবে আপনি এটি ফ্রিবিএসডি-তে কাজ করতে চান না তবে উদাহরণস্বরূপ।
ধরে নিই যে আপনি একটি স্ট্যান্ডার্ড লিনাক্স সমাধান সন্ধান করছেন, এটি অর্জনের জন্য তুলনামূলকভাবে সোজা উপায় সহ find
:
find dir1/ dir2/ -maxdepth 1 -type f | wc -l
যেখানে find
দুটি নির্দিষ্ট সাব-ডাইরেক্টরিগুলিকে অনুসরণ করে সেখানে -maxdepth
1 এর একটিতে যা আরও পুনরাবৃত্তি রোধ করে এবং কেবল -type f
নিউলাইন দ্বারা পৃথক করা ফাইল ( ) প্রতিবেদন করে । ফলাফলটি wc
সেই লাইনের সংখ্যা গণনা করতে পাইপ করা হয়।
find . -maxdepth 1 -type d
আউটপুটটির সাথে একত্রিত করতে পারি ?
find $dirs ...
(খ) যদি সেগুলি কেবলমাত্র সেই ডিরেক্টরি থেকে একটি উচ্চ স্তরের ডিরেক্টরিতে থাকে তবেfind */ ...
-exec echo
আপনার find কমান্ডের করুন - যে ভাবে এটা ফাইলের নাম echo নয়, শুধু একটি newline।
"পুনরাবৃত্তি ছাড়াই", এর অর্থ কি আপনার যদি বোঝা যাচ্ছে যে যদি directoryName1
সাব-ডাইরেক্টরিগুলি থাকে তবে আপনি সাব-ডিরেক্টরিতে ফাইলগুলি গণনা করতে চান না? যদি তা হয় তবে নির্দেশিত ডিরেক্টরিগুলিতে নিয়মিত সমস্ত ফাইল গণনা করার একটি উপায় এখানে রয়েছে:
count=0
for d in directoryName1 directoryName2; do
for f in "$d"/* "$d"/.[!.]* "$d"/..?*; do
if [ -f "$f" ]; then count=$((count+1)); fi
done
done
নোট করুন যে -f
পরীক্ষাটি দুটি ফাংশন সম্পাদন করে: এটি উপরের গ্লোবগুলির মধ্যে একটির সাথে মিলিত এন্ট্রি একটি নিয়মিত ফাইল কিনা তা পরীক্ষা করে এবং এটি পরীক্ষা করে যে এন্ট্রিটি ম্যাচ ছিল কিনা (যদি কোনও গ্লোবগুলির মধ্যে কোনও কিছুই মিলে না, তবে প্যাটার্নটি যেমন রয়েছে তেমন থাকে)। যদি আপনি প্রদত্ত ডিরেক্টরিগুলিতে নির্বিশেষে সমস্ত এন্ট্রি গণনা করতে চান তবে এর -f
সাথে প্রতিস্থাপন করুন -e
।
Ksh এর সাথে প্যাটার্নগুলি ডট ফাইলগুলি মেলে তৈরি করার এবং খালি তালিকা তৈরির উপায় রয়েছে যদি কোনও ফাইল কোনও প্যাটার্নের সাথে মেলে না। সুতরাং ksh এ আপনি নিয়মিত ফাইলগুলি গণনা করতে পারেন:
FIGNORE='.?(.)'
count=0
for x in ~(N)directoryName1/* ~(N)directoryName2/*; do
if [ -f "$x" ]; then ((++count)); fi
done
বা সমস্ত ফাইল কেবল এইভাবে:
FIGNORE='.?(.)'
files=(~(N)directoryName1/* ~(N)directoryName2/*)
count=${#files}
এটিকে আরও সহজ করার জন্য বাশের বিভিন্ন উপায় রয়েছে। নিয়মিত ফাইলগুলি গণনা করতে:
shopt -s dotglob nullglob
count=0
for x in directoryName1/* directoryName2/*; do
if [ -f "$x" ]; then ((++count)); fi
done
সমস্ত ফাইল গণনা করতে:
shopt -s dotglob nullglob
files=(directoryName1/* directoryName2/*)
count=${#files}
যথারীতি, zsh এ এটি আরও সহজ। নিয়মিত ফাইলগুলি গণনা করতে:
files=({directoryName1,directoryName2}/*(DN.))
count=$#files
সমস্ত ফাইল গণনা (DN.)
করতে পরিবর্তন করুন (DN)
।
¹ নোট করুন যে প্রতিটি প্যাটার্ন নিজেই মেলে, অন্যথায় ফলাফলগুলি বন্ধ হতে পারে (যেমন আপনি যদি একটি অঙ্ক দিয়ে শুরু করা ফাইলগুলি গণনা করছেন তবে আপনি কেবল এটি করতে পারবেন না for x in [0-9]*; do if [ -f "$x" ]; then …
কারণ সেখানে কোনও ফাইল বলা হতে পারে [0-9]foo
)।
একটি উপর ভিত্তি করে গণনা স্ক্রিপ্ট , শন এর উত্তর এবং ব্যাশ কৌতুক নিশ্চিত এমনকি ফাইলের নামের নতুন লাইন সঙ্গে একটি একক লাইন একটি ব্যবহারযোগ্য আকারে ছাপা হয় করতে:
for f in *
do
if [ -d "./$f" ]
then
printf %q "$f"
printf %s ' '
find "$f" -maxdepth 1 -printf x | wc -c
fi
done
printf %q
স্ট্রিংয়ের একটি উদ্ধৃত সংস্করণ প্রিন্ট করা হয়, এটি হল একটি একক-রেখার স্ট্রিং যা আপনি বাশ স্ক্রিপ্টে আক্ষরিক স্ট্রিং হিসাবে ব্যাখ্যা করতে (সম্ভাব্য) নিউলাইন এবং অন্যান্য বিশেষ অক্ষরগুলি সহ ব্যাখ্যা করতে পারেন। উদাহরণস্বরূপ, echo -n $'\tfoo\nbar'
বনাম দেখুন printf %q $'\tfoo\nbar'
।
find
কমান্ড কেবল প্রতিটি ফাইলের জন্য একটি একক অক্ষর মুদ্রণ, এবং তারপর কাউন্টিং লাইনের পরিবর্তে ঐ গণনা করে কাজ করে।
এখানে একটি "বলপূর্বক" পর আপনার ফলাফল পেতে উপায় ব্যবহার find
, echo
, ls
, wc
, xargs
এবং awk
।
find . -maxdepth 1 -type d -exec sh -c "echo '{}'; ls -1 '{}' | wc -l" \; | xargs -n 2 | awk '{print $1" "$2}'
for i in *; do echo $i; ls $i | wc -l; done
for i in `ls -1`; do echo $i : `ls -1 $i|wc -l`; done
find
বাশ কখন করবে আপনি কেন ব্যবহার করতে চান ?(shopt -s dotglob; for dir in */; do all=("$dir"/*); echo "$dir: ${#all[@]}"; done)
: সমস্ত ডিরেক্টরিতে, সেই ডিরেক্টরিতে প্রবেশের সংখ্যা গণনা করুন (লুকানো ডট ফাইল সহ, বাদে.
এবং..
)