আমি বুঝতে পারি যে ls -R
ডিরেক্টরিগুলির একটি তালিকা প্রদর্শন করে। তবে কেন এটি পুনরাবৃত্তি হয়? প্রক্রিয়াটিতে পুনরাবৃত্তি কীভাবে ব্যবহৃত হয়?
ls
কোনও ডিরেক্টরি যখন মুখোমুখি হয় তখন এটি निर्देशिकाটি পুনরাবৃত্তভাবে তালিকাভুক্ত করে।
আমি বুঝতে পারি যে ls -R
ডিরেক্টরিগুলির একটি তালিকা প্রদর্শন করে। তবে কেন এটি পুনরাবৃত্তি হয়? প্রক্রিয়াটিতে পুনরাবৃত্তি কীভাবে ব্যবহৃত হয়?
ls
কোনও ডিরেক্টরি যখন মুখোমুখি হয় তখন এটি निर्देशिकाটি পুনরাবৃত্তভাবে তালিকাভুক্ত করে।
উত্তর:
প্রথমে, একটি স্বেচ্ছাসেবী ফোল্ডার কাঠামো সংজ্ঞায়িত করা যাক:
.
├── a1 [D]
│ ├── b1 [D]
│ │ ├── c1
│ │ ├── c2 [D]
│ │ │ ├── d1
│ │ │ ├── d2
│ │ │ └── d3
│ │ ├── c3
│ │ ├── c4
│ │ └── c5
│ └── b2 [D]
│ ├── c6
│ └── c7
├── a2 [D]
│ ├── b3 [D]
│ │ ├── c8
│ │ └── c9
│ └── b4 [D]
│ ├── c10
│ └── c11
├── a3 [D]
│ ├── b5
│ ├── b6
│ └── b7
└── a4 [D]
আমরা যখন করি ls
, কেবলমাত্র বেস ফোল্ডারের আউটপুট আমরা পাই:
a1 a2 a3 a4
তবে, আমরা যখন ফোন করি তখন আমরা ls -R
কিছু আলাদা পাই:
.:
a1 a2 a3 a4
./a1:
b1 b2
./a1/b1:
c1 c2 c3 c4 c5
./a1/b1/c2:
d1 d2 d3
./a1/b2:
c6 c7
./a2:
b3 b4
./a2/b3:
c8 c9
./a2/b4:
c10 c11
./a3:
b5 b6 b7
./a4:
আপনি দেখতে পাচ্ছেন যে ls
এটি বেস ফোল্ডারে চলছে এবং তারপরে সমস্ত শিশু ফোল্ডার। এবং সমস্ত নাতনী ফোল্ডার, বিজ্ঞাপন অন্তর্ভুক্ত। কার্যকরভাবে, কমান্ডটি প্রতিটি ফোল্ডারটিকে পুনরাবৃত্তভাবে চলবে যতক্ষণ না এটি ডিরেক্টরি ট্রিটির শেষের দিকে না যায়। এই মুহুর্তে, এটি গাছের একটি শাখা ফিরে আসে এবং কোনও সাব-ফোল্ডারগুলির জন্য একই কাজ করে, যদি কোনও হয়।
বা, সিউডো কোডে:
recursivelyList(directory) {
files[] = listDirectory(directory) // Get all files in the directory
print(directory.name + ":\n" + files.join(" ")) // Print the "ls" output
for (file : files) { // Go through all the files in the directory
if (file.isDirectory()) { // Check if the current file being looked at is a directory
recursivelyList(directory) // If so, recursively list that directory
}
}
}
এবং কারণ আমি করতে পারি, একই রেফারেন্স জাভা বাস্তবায়ন ।
বাস্তবে, আপনি জিজ্ঞাসা করতে পারেন দুটি ঘনিষ্ঠভাবে মিলিত প্রশ্ন রয়েছে।
ls
? আপনার মুখবন্ধ ("প্রক্রিয়াটিতে পুনরাবৃত্তি কীভাবে ব্যবহৃত হয়?") থেকে, আমি মনে করি এটি আপনি যা জানতে চান এটির একটি অংশ। এই উত্তরটি সেই প্রশ্নের সমাধান করে।ls
পুনরাবৃত্ত কৌশল দ্বারা প্রয়োগ করা বোধগম্য :FOLDOC পুনরাবৃত্তি হিসাবে সংজ্ঞা দেয় :
যখন কোনও ফাংশন (বা পদ্ধতি ) নিজেকে কল করে। এই জাতীয় ফাংশনটিকে "পুনরাবৃত্ত" বলা হয়। যদি কলটি এক বা একাধিক ফাংশনের মাধ্যমে হয় তবে এই গ্রুপ ফাংশনটিকে "পারস্পরিক পুনরাবৃত্তি" বলা হয়।
বাস্তবায়নের প্রাকৃতিক উপায় ls
হ'ল এমন একটি ফাংশন লিখুন যা প্রদর্শিত হবে ফাইল সিস্টেমের এন্ট্রিগুলির একটি তালিকা তৈরি করে এবং পাথ এবং বিকল্প আর্গুমেন্টগুলি প্রসেস করার জন্য এবং অন্যান্য কোডগুলি পছন্দসই হিসাবে প্রদর্শন করে write এই ফাংশনটি পুনরাবৃত্তভাবে কার্যকর করা সম্ভব।
বিকল্প প্রক্রিয়া চলাকালীন, ls
এটি পুনরুক্তিভাবে পরিচালনা করতে বলা হয়েছে কিনা তা নির্ধারণ করবে ( -R
পতাকাটির সাথে ডাক দিয়ে )। যদি তাই হয় তবে প্রদর্শিত ফাংশনটি প্রদর্শিত এন্ট্রিগুলির একটি তালিকা তৈরি করে .
এবং এটি বাদে প্রতিটি ডিরেক্টরি এটি তালিকাভুক্ত করে তার জন্য একবার কল করবে ..
। এই ফাংশনটির পৃথক পুনরাবৃত্ত এবং নন-সংস্করণীয় সংস্করণ থাকতে পারে, বা ফাংশনটি প্রতিবার এটি পুনরাবৃত্তভাবে অপারেট করা হচ্ছে বলে মনে করা যেতে পারে।
উবুন্টু /bin/ls
, এক্সিকিউটেবল যা আপনি চালনার সময় সঞ্চালিত ls
হয়, এটি জিএনইউ কোরিউটিলস সরবরাহ করে এবং এর অনেকগুলি বৈশিষ্ট্য রয়েছে। ফলস্বরূপ, এর কোডটি আপনি প্রত্যাশার চেয়ে কিছুটা দীর্ঘ এবং আরও জটিল। তবে উবুন্টুতে একটি সহজ সংস্করণ রয়েছে ls
যা বুসিবক্স সরবরাহ করে । আপনি এটি টাইপ করে চালাতে পারেন busybox ls
।
busybox ls
পুনরাবৃত্তি কীভাবে ব্যবহার করে:ls
ব্যাসিবক্স ইন বাস্তবায়িত হয় coreutils/ls.c
। এটিতে একটি scan_and_display_dirs_recur()
ফাংশন রয়েছে যা ডিরেক্টরি গাছটিকে পুনরাবৃত্তভাবে মুদ্রণের জন্য অনুরোধ করা হয়:
static void scan_and_display_dirs_recur(struct dnode **dn, int first)
{
unsigned nfiles;
struct dnode **subdnp;
for (; *dn; dn++) {
if (G.all_fmt & (DISP_DIRNAME | DISP_RECURSIVE)) {
if (!first)
bb_putchar('\n');
first = 0;
printf("%s:\n", (*dn)->fullname);
}
subdnp = scan_one_dir((*dn)->fullname, &nfiles);
#if ENABLE_DESKTOP
if ((G.all_fmt & STYLE_MASK) == STYLE_LONG || (G.all_fmt & LIST_BLOCKS))
printf("total %"OFF_FMT"u\n", calculate_blocks(subdnp));
#endif
if (nfiles > 0) {
/* list all files at this level */
sort_and_display_files(subdnp, nfiles);
if (ENABLE_FEATURE_LS_RECURSIVE
&& (G.all_fmt & DISP_RECURSIVE)
) {
struct dnode **dnd;
unsigned dndirs;
/* recursive - list the sub-dirs */
dnd = splitdnarray(subdnp, SPLIT_SUBDIR);
dndirs = count_dirs(subdnp, SPLIT_SUBDIR);
if (dndirs > 0) {
dnsort(dnd, dndirs);
scan_and_display_dirs_recur(dnd, 0);
/* free the array of dnode pointers to the dirs */
free(dnd);
}
}
/* free the dnodes and the fullname mem */
dfree(subdnp);
}
}
}
পুনরাবৃত্তির ফাংশন কলটি লাইন করায় তা হ'ল:
scan_and_display_dirs_recur(dnd, 0);
আপনি যদি busybox ls
কোনও ডিবাগারে চালিত হন তবে আপনি এটি অপারেশনটিতে দেখতে পাবেন । প্রথম ইনস্টলের ডিবাগ চিহ্ন দ্বারা -dbgsym.ddeb প্যাকেজ সক্রিয় এবং তারপর ইনস্টল busybox-static-dbgsym
প্যাকেজ। gdb
পাশাপাশি ইনস্টল করুন (এটিই ডিবাগার)।
sudo apt-get update
sudo apt-get install gdb busybox-static-dbgsym
আমি coreutils ls
একটি সাধারণ ডিরেক্টরি ট্রিতে ডিবাগ করার পরামর্শ দিই ।
আপনার যদি কোনও সুবিধাজনক না হয় তবে একটি তৈরি করুন (এটি উইনউইউচস 2 ইউনিক্সের উত্তরেরmkdir -p
কমান্ডের মতোই কাজ করে ):
mkdir -pv foo/{bar/foobar,baz/quux}
এবং এটিকে কিছু ফাইল দিয়ে বিশিষ্ট করুন:
(shopt -s globstar; for d in foo/**; do touch "$d/file$((i++))"; done)
আপনি busybox ls -R foo
এই আউটপুট উত্পাদন করে প্রত্যাশিত হিসাবে কাজগুলি যাচাই করতে পারেন :
foo:
bar baz file0
foo/bar:
file1 foobar
foo/bar/foobar:
file2
foo/baz:
file3 quux
foo/baz/quux:
file4
busybox
ডিবাগারে খুলুন :
gdb busybox
জিডিবি নিজের সম্পর্কে কিছু তথ্য মুদ্রণ করবে। তারপরে এটির মতো কিছু বলা উচিত:
Reading symbols from busybox...Reading symbols from /usr/lib/debug/.build-id/5c/e436575b628a8f54c2a346cc6e758d494c33fe.debug...done.
done.
(gdb)
(gdb)
ডিবাগারটিতে আপনার প্রম্পট। আপনি প্রথমে জিডিবিকে এই প্রম্পটে যা করতে বলবেন তা হ'ল scan_and_display_dirs_recur()
ফাংশনটির শুরুতে একটি ব্রেকপয়েন্ট সেট করা :
b scan_and_display_dirs_recur
আপনি যখন এটি চালান, জিডিবি আপনাকে এমন কিছু বলা উচিত:
Breakpoint 1 at 0x5545b4: file coreutils/ls.c, line 1026.
এখন জিডিবিকে তার যুক্তি হিসাবে (বা যে কোনও ডিরেক্টরি নাম যা চান) busybox
দিয়ে চালাতে বলুন :ls -R foo
run ls -R foo
আপনি এরকম কিছু দেখতে পাবেন:
Starting program: /bin/busybox ls -R foo
Breakpoint 1, scan_and_display_dirs_recur (dn=dn@entry=0x7e6c60, first=1) at coreutils/ls.c:1026
1026 coreutils/ls.c: No such file or directory.
আপনি যদি No such file or directory
উপরে দেখতে পারেন তবে ঠিক আছে। এই বিক্ষোভের উদ্দেশ্যটি কেবল scan_and_display_dirs_recur()
ফাংশনটি কখন ডাকা হয়েছে তা দেখার জন্য, তাই GDB কে প্রকৃত উত্স কোড পরীক্ষা করার দরকার নেই।
লক্ষ্য করুন যে কোনও ডিরেক্টরি এন্ট্রি মুদ্রিত হওয়ার আগেই ডিবাগারটি ব্রেকপয়েন্টে গিয়েছিল। এটি সেই ফাংশনটির প্রবেশদ্বারে ভেঙে যায় তবে সেই ফাংশনের কোডটি মুদ্রণের জন্য কোনও ডিরেক্টরি গণনার জন্য চালানো উচিত।
জিডিবিকে চালিয়ে যেতে বলতে, চালান:
c
প্রতিবার scan_and_display_dirs_recur()
বলা হয়, ব্রেকপয়েন্টটি আবার আঘাত হানে, তাই আপনি ক্রিয়াকলাপটি দেখতে পাবেন। দেখে মনে হচ্ছে এটি ( (gdb)
প্রম্পট এবং আপনার আদেশগুলি সহ ):
(gdb) c
Continuing.
foo:
bar baz file0
Breakpoint 1, scan_and_display_dirs_recur (dn=dn@entry=0x7e6cb0, first=first@entry=0) at coreutils/ls.c:1026
1026 in coreutils/ls.c
(gdb) c
Continuing.
foo/bar:
file1 foobar
Breakpoint 1, scan_and_display_dirs_recur (dn=dn@entry=0x7e6cf0, first=first@entry=0) at coreutils/ls.c:1026
1026 in coreutils/ls.c
(gdb) c
Continuing.
foo/bar/foobar:
file2
foo/baz:
file3 quux
Breakpoint 1, scan_and_display_dirs_recur (dn=dn@entry=0x7e6cf0, first=first@entry=0) at coreutils/ls.c:1026
1026 in coreutils/ls.c
(gdb) c
Continuing.
foo/baz/quux:
file4
[Inferior 1 (process 2321) exited normally]
ফাংশনটির recur
নামে রয়েছে ... -R
পতাকাটি দেওয়া হলে ব্যাসিবক্স কি কেবল এটি ব্যবহার করে ? ডিবাগারে, এটি সন্ধান করা সহজ:
(gdb) run ls foo
Starting program: /bin/busybox ls foo
Breakpoint 1, scan_and_display_dirs_recur (dn=dn@entry=0x7e6c60, first=1) at coreutils/ls.c:1026
1026 in coreutils/ls.c
(gdb) c
Continuing.
bar baz file0
[Inferior 1 (process 2327) exited normally]
এমনকি বাইরেও, ফাইল সিস্টেমের এন্ট্রিগুলি কী রয়েছে তা সনাক্ত করতে এবং তাদের দেখানোর জন্য -R
এই নির্দিষ্ট প্রয়োগটি ls
একই ফাংশনটি ব্যবহার করে।
আপনি যখন ডিবাগারটি ছাড়তে চান, কেবল এটি বলুন:
q
scan_and_display_dirs_recur()
এটি নিজেই ফোন করা উচিত কিনা কীভাবে জানেন:বিশেষত -R
পতাকাটি পাস হওয়ার পরে এটি কীভাবে আলাদাভাবে কাজ করবে ? উত্স কোড পরীক্ষা করা (এটি আপনার উবুন্টু সিস্টেমে সঠিক সংস্করণ নাও হতে পারে) প্রকাশ করে যে এটি তার অভ্যন্তরীণ ডেটা কাঠামোটি পরীক্ষা করে G.all_fmt
, যেখানে এটি কোন বিকল্পগুলির সাথে অনুরোধ করা হয়েছে তা সংরক্ষণ করে:
if (ENABLE_FEATURE_LS_RECURSIVE
&& (G.all_fmt & DISP_RECURSIVE)
(যদি ব্যাসিবক্সকে সমর্থন না করে সংকলিত করা হয় -R
, তবে এটি ফাইল সিস্টেমের এন্ট্রিগুলিকেও পুনরাবৃত্তভাবে প্রদর্শন করার চেষ্টা করবে না; ENABLE_FEATURE_LS_RECURSIVE
অংশটি এটিই what
G.all_fmt & DISP_RECURSIVE
সত্য হলেই কেবল কোডটি পুনরাবৃত্তিকারী ফাংশন কল চালায়।
struct dnode **dnd;
unsigned dndirs;
/* recursive - list the sub-dirs */
dnd = splitdnarray(subdnp, SPLIT_SUBDIR);
dndirs = count_dirs(subdnp, SPLIT_SUBDIR);
if (dndirs > 0) {
dnsort(dnd, dndirs);
scan_and_display_dirs_recur(dnd, 0);
/* free the array of dnode pointers to the dirs */
free(dnd);
}
অন্যথায়, ফাংশনটি কেবল একবার চালায় (কমান্ড লাইনে নির্দিষ্ট ডিরেক্টরি প্রতি)।
আপনি যখন এটির বিষয়ে চিন্তা করেন, "পুনরাবৃত্তিশীল" ডিরেক্টরি এবং তাদের ফাইল এবং ডিরেক্টরি এবং তাদের ফাইল এবং ডিরেক্টরি এবং তাদের ফাইল এবং ডিরেক্টরি এবং তাদের ফাইলগুলিতে কাজ করে এমন কমান্ডগুলির জন্য অর্থবোধ করে .........
.... নির্দিষ্ট পয়েন্ট ডাউন থেকে পুরো গাছটি কমান্ড দ্বারা চালিত না হওয়া পর্যন্ত, এক্ষেত্রে যে কোনও উপ-ডিরেক্টরিগুলির যে কোনও সাব-ডিরেক্টরিতে যে কোনও সাব-ডাইরেক্টরিজের সামগ্রীগুলি তালিকাভুক্ত করা হচ্ছে .......... যা এর অধীনে বিদ্যমান কমান্ডের যুক্তি (গুলি)
-আর পুনরাবৃত্তি জন্য, যা আলগাভাবে "বারবার" বলা যেতে পারে "
উদাহরণস্বরূপ এই কোডটি নিন:
───────────────────────────────────────────────────────────────────────────────
$ mkdir -p temp/a
───────────────────────────────────────────────────────────────────────────────
$ mkdir -p temp/b/1
───────────────────────────────────────────────────────────────────────────────
$ mkdir -p temp/c/1/2
───────────────────────────────────────────────────────────────────────────────
$ ls -R temp
temp:
a b c
temp/a:
temp/b:
1
temp/b/1:
temp/c:
1
temp/c/1:
2
temp/c/1/2:
-p
ডিরেক্টরি তৈরীর আপনি ভর একটি একক কমান্ডের সাহায্যে ডিরেক্টরি তৈরি করতে পারবেন। যদি এক বা একাধিক শীর্ষ-মধ্যবর্তী ডিরেক্টরি ইতিমধ্যে উপস্থিত থাকে তবে এটি ত্রুটি নয় এবং মধ্য-নিম্ন ডিরেক্টরিগুলি তৈরি করা হয়।
তারপরে ls -R
অবিচ্ছিন্নভাবে প্রতিটি একক ডিরেক্টরি টেম্পের সাথে শুরু করে এবং গাছের নীচে সমস্ত শাখায় কাজ করার তালিকা তৈরি করে।
এখন ls -R
কমান্ডের পরিপূরক , অর্থাৎ tree
কমান্ডটি দেখুন:
$ tree temp
temp
├── a
├── b
│ └── 1
└── c
└── 1
└── 2
6 directories, 0 files
আপনি tree
যেমন দেখতে পান তেমন সফল হয় ls -R
তবে আরও সংক্ষিপ্ত এবং আমি "প্রিটিয়ার" বলার সাহস করি।
এখন আসুন আমরা কীভাবে একটি সাধারণ কমান্ডের সাহায্যে তৈরি করা ডিরেক্টরিগুলি পুনরাবৃত্তভাবে মুছে ফেলি তা দেখুন:
$ rm -r temp
এটি পুনরাবৃত্তভাবে মুছে ফেলা হয় temp
এবং এর নীচে সমস্ত উপ-ডিরেক্টরি। যেমন temp/a
, temp/b/1
এবং temp/c/1/2
এর মধ্যে মধ্যবর্তী ডিরেক্টরিগুলিও।
tree
যদিও। এটি একটি দুর্দান্ত সরঞ্জাম।
এখানে একটি সহজ ব্যাখ্যা, এটি বোধগম্য কারণ কারণ যখন এটি উপ-ডিরেক্টরিগুলির বিষয়বস্তু প্রদর্শন করার কথা আসে, একই ফাংশনটি ইতিমধ্যে জানে যে কোনও ডিরেক্টরিতে কী করা উচিত। সুতরাং ফলাফলটি পেতে কেবল প্রতিটি উপ-ডিরেক্টরিতে নিজেকে কল করা দরকার!
সিউডোকোডে এটি দেখতে এরকম কিছু দেখাচ্ছে:
recursive_ls(dir)
print(files and directories)
foreach (directoriy in dir)
recursive_ls(directory)
end foreach
end recursive_ls