সমস্ত উপ-ডিরেক্টরিতে ফাইল সংখ্যা রিপোর্ট করবেন কীভাবে?


24

আমাকে সমস্ত উপ-ডিরেক্টরিগুলি পরিদর্শন করতে হবে এবং কতগুলি ফাইল রয়েছে (তাদের পূর্বে পুনরাবৃত্তি ছাড়াই) তা রিপোর্ট করতে হবে:

directoryName1 numberOfFiles
directoryName2 numberOfFiles

findবাশ কখন করবে আপনি কেন ব্যবহার করতে চান ? (shopt -s dotglob; for dir in */; do all=("$dir"/*); echo "$dir: ${#all[@]}"; done): সমস্ত ডিরেক্টরিতে, সেই ডিরেক্টরিতে প্রবেশের সংখ্যা গণনা করুন (লুকানো ডট ফাইল সহ, বাদে .এবং ..)
janmoesen

@janmoesen আপনি কেন এই উত্তরটি দেননি? আমি স্ক্রিপ্টিং শেল নতুন, কিন্তু আমি আপনার পদ্ধতি সঙ্গে কোন গেটচ দেখতে পাচ্ছি না। আমার কাছে এটি দেখতে সবচেয়ে ভাল উপায়। আপনার মন্তব্য কেউ আপত্তি করেনি, তবে এটি কেন খারাপ হতে পারে সে সম্পর্কে কেউ মন্তব্য করেনি। আপগ্রেটেড উত্তরগুলির চেয়ে আপনার চেয়ে আরও বেশি প্রতিক্রিয়া রয়েছে তাই এটি আমার অবাক করে দেয় যে আমি কিছু মিস করছি কিনা।
toxalot

@ টক্সালোট: আমি এটিকে উত্তর হিসাবে যুক্ত করা বিরক্ত করিনি কারণ এটি খুব সংক্ষিপ্ত ছিল (এবং সম্ভবত স্বরটিতে কিছুটা কমল)। মন্তব্য upvote নির্দ্বিধায়। :-) এছাড়াও, "কত ফাইল" এর অর্থ কী তা নিয়ে প্রশ্নটি কিছুটা অস্পষ্ট। আমার সমাধান "নিয়মিত" ফাইল এবং ডিরেক্টরি গণনা করে ; সম্ভবত পোস্টারটির অর্থ "ফাইল নয় ডিরেক্টরিগুলি"। আরেকটি বিষয় মনে রাখবেন যে এই গ্লোব্বিং "গোপন" ডট ফাইলগুলিকে বিবেচনা করে না। যদিও got উভয়ের গ্যাটাচকে প্রায় কাছাকাছি উপায় রয়েছে। তবে আবার: মূল পোস্টারের সঠিক প্রয়োজনীয়তার বিষয়ে নিশ্চিত নই।
janmoesen

উত্তর:


30

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

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 {} \;। আমি কেবল ফাইলগুলি টালাই করার উদ্দেশ্যে একটি নতুন লাইন মুদ্রণ করতে চাই।


1
কেন পৃথিবীতে এমন কেউ আছেন যারা ফাইলের নামে নতুন লাইনের ব্যবহার করেন? উত্তর করার জন্য ধন্যবাদ.
শাইবয়

1
আমি বিশ্বাস করি ফাইলের নামগুলিতে / এবং নাল অক্ষর ব্যতীত অন্য কোনও অক্ষর থাকতে পারে। dwheeler.com/essays/fixing-unix-linux-filenames.html
Flimm

2
গণনা নিজেই ডিরেক্টরি অন্তর্ভুক্ত করবে। আপনি বাদ দেওয়ার যে গণনা, ব্যবহার থেকে চান-mindepth 1
toxalot

আপনি -printf '\n'পরিবর্তে ব্যবহার করতে পারে -exec echo
toxalot

1
@ টক্সলোট আপনি যদি এমন কোনও সমর্থন খুঁজে পেয়ে থাকেন যা সমর্থন করে -printfতবে আপনি এটি ফ্রিবিএসডি-তে কাজ করতে চান না তবে উদাহরণস্বরূপ।
শন জে গফ

6

ধরে নিই যে আপনি একটি স্ট্যান্ডার্ড লিনাক্স সমাধান সন্ধান করছেন, এটি অর্জনের জন্য তুলনামূলকভাবে সোজা উপায় সহ find:

find dir1/ dir2/ -maxdepth 1 -type f | wc -l

যেখানে findদুটি নির্দিষ্ট সাব-ডাইরেক্টরিগুলিকে অনুসরণ করে সেখানে -maxdepth1 এর একটিতে যা আরও পুনরাবৃত্তি রোধ করে এবং কেবল -type fনিউলাইন দ্বারা পৃথক করা ফাইল ( ) প্রতিবেদন করে । ফলাফলটি wcসেই লাইনের সংখ্যা গণনা করতে পাইপ করা হয়।


আমার 2 টিরও বেশি ডায়ার রয়েছে ... আমি কীভাবে আপনার আদেশটি find . -maxdepth 1 -type dআউটপুটটির সাথে একত্রিত করতে পারি ?
শাইবয়

আপনি হয় (ক) পরিবর্তনশীল এবং প্রয়োজনীয় প্রয়োজনীয় ডিরেক্টরিগুলি অন্তর্ভুক্ত করতে পারেন এবং find $dirs ...(খ) যদি সেগুলি কেবলমাত্র সেই ডিরেক্টরি থেকে একটি উচ্চ স্তরের ডিরেক্টরিতে থাকে তবেfind */ ...
জেসনওয়ারিয়ান

1
কোনও ফাইলনামে এটির একটি নতুন লাইন অক্ষর থাকলে এটি ভুল ফলাফলের প্রতিবেদন করবে।
শন জে গফ

@ শাহান: ধন্যবাদ আমি ভেবেছিলাম আমার কাছে ফাঁকা জায়গাগুলির ফাইল নাম রয়েছে, তবে নতুন লাইনগুলি বিবেচনা করা হয়নি: সমাধানের জন্য কোনও পরামর্শ?
জেসনওয়ারিয়ান

যোগ -exec echoআপনার find কমান্ডের করুন - যে ভাবে এটা ফাইলের নাম echo নয়, শুধু একটি newline।
শন জে গফ

5

"পুনরাবৃত্তি ছাড়াই", এর অর্থ কি আপনার যদি বোঝা যাচ্ছে যে যদি 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)।


2

একটি উপর ভিত্তি করে গণনা স্ক্রিপ্ট , শন এর উত্তর এবং ব্যাশ কৌতুক নিশ্চিত এমনকি ফাইলের নামের নতুন লাইন সঙ্গে একটি একক লাইন একটি ব্যবহারযোগ্য আকারে ছাপা হয় করতে:

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কমান্ড কেবল প্রতিটি ফাইলের জন্য একটি একক অক্ষর মুদ্রণ, এবং তারপর কাউন্টিং লাইনের পরিবর্তে ঐ গণনা করে কাজ করে।


1

এখানে একটি "বলপূর্বক" পর আপনার ফলাফল পেতে উপায় ব্যবহার 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}'

এই কাজ. তবে আপনার যদি ডায়ার থাকে যে নামে `। স্থান আছে আউটপুট গণ্ডগোল।
শাইবয়

কোনও ফাইলনামে এটির একটি নতুন লাইন অক্ষর থাকলে এটি ভুল ফলাফলের প্রতিবেদন করবে।
শন জে গফ

-1
for i in *; do echo $i; ls $i | wc -l; done

4
U&L এ আপনাকে স্বাগতম। উত্তরগুলি কেবল কোড ড্রপ নয়, ব্যাখ্যা সহ দীর্ঘ ফর্মযুক্ত হওয়া উচিত। দয়া করে এটি প্রসারিত করুন এবং কী চলছে তা ব্যাখ্যা করুন। এছাড়াও এটি এটি করার একটি খুব অযোগ্য উপায় এবং উদাহরণস্বরূপ, স্পেস সহ ফাইলগুলি পরিচালনা করে না।
slm

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