এলএস -আরকে "পুনরাবৃত্ত" তালিকা বলা হয় কেন?


36

আমি বুঝতে পারি যে ls -Rডিরেক্টরিগুলির একটি তালিকা প্রদর্শন করে। তবে কেন এটি পুনরাবৃত্তি হয়? প্রক্রিয়াটিতে পুনরাবৃত্তি কীভাবে ব্যবহৃত হয়?


12
স্বজ্ঞাততা হ'ল ডিরেক্টরি এবং তাদের উপ-ডিরেক্টরিগুলি সহজেই একটি গাছ ব্যবহার করে মডেল করা যায়। হাঁটার গাছগুলিতে অ্যালগরিদমগুলি সাধারণত পুনরাবৃত্ত হয়।
কেভিন - মনিকা

1
@ কেভিন আমি মনে করি না যে প্রতিটি প্রশ্নের উত্তর দেওয়ার জন্য গাছের ধারণাটি উত্থাপন করার কোনও দরকার আছে - উত্তরটি কেবলমাত্র এমন lsকোনও ডিরেক্টরি যখন মুখোমুখি হয় তখন এটি निर्देशिकाটি পুনরাবৃত্তভাবে তালিকাভুক্ত করে।
ব্যবহারকারী 253751

উত্তর:


67

প্রথমে, একটি স্বেচ্ছাসেবী ফোল্ডার কাঠামো সংজ্ঞায়িত করা যাক:

.
├── 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
        }
    }
}

এবং কারণ আমি করতে পারি, একই রেফারেন্স জাভা বাস্তবায়ন


23

বাস্তবে, আপনি জিজ্ঞাসা করতে পারেন দুটি ঘনিষ্ঠভাবে মিলিত প্রশ্ন রয়েছে।

  • ফাইলসাইম হায়ারার্কিতে প্রতিটি প্রবেশের জন্য হাঁটার প্রক্রিয়াটি কেন একটি অন্তর্নিহিত পুনরাবৃত্ত প্রক্রিয়া? এটি জানা এবং কাজ ওল্ফের মতো অন্যান্য উত্তরগুলির দ্বারা সম্বোধন করা হয়েছে ।
  • কিভাবে পুনরাবৃত্তি কৌশল প্রয়োগে ব্যবহার করা হয় 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);
                }

অন্যথায়, ফাংশনটি কেবল একবার চালায় (কমান্ড লাইনে নির্দিষ্ট ডিরেক্টরি প্রতি)।


আবার, এলিয়াহ একটি হাইপার-বিস্তৃত উত্তর নিয়ে আসে। একটি ভাল প্রাপ্য +1।
কাজ ওল্ফ

2
ওহ, সুতরাং এটি পুচ্ছ পুনরাবৃত্তিও নয়। এর অর্থ অবশ্যই সেখানে কিছু ডিরেক্টরি সামগ্রীর উপস্থিতি রয়েছে, তালিকাবদ্ধকরণ যা স্ট্যাক ওভারফ্লোর কারণে ব্যস্তবক্সকে ক্র্যাশ করবে (যদিও এটি অত্যন্ত গভীর নেস্টিং হতে চাই)।
রুস্লান

2
এটি অবাক করা। আপনি ডিবাগিংয়ের জন্য প্রাথমিকভাবে ওপি সরবরাহ করেছিলেন যাতে তারা বুঝতে পারে যে জিনিসটি কীভাবে কাজ করছে। চমত্কার।
আন্ড্রেয়া লাজারোত্তো 24'17

16

আপনি যখন এটির বিষয়ে চিন্তা করেন, "পুনরাবৃত্তিশীল" ডিরেক্টরি এবং তাদের ফাইল এবং ডিরেক্টরি এবং তাদের ফাইল এবং ডিরেক্টরি এবং তাদের ফাইল এবং ডিরেক্টরি এবং তাদের ফাইলগুলিতে কাজ করে এমন কমান্ডগুলির জন্য অর্থবোধ করে .........

.... নির্দিষ্ট পয়েন্ট ডাউন থেকে পুরো গাছটি কমান্ড দ্বারা চালিত না হওয়া পর্যন্ত, এক্ষেত্রে যে কোনও উপ-ডিরেক্টরিগুলির যে কোনও সাব-ডিরেক্টরিতে যে কোনও সাব-ডাইরেক্টরিজের সামগ্রীগুলি তালিকাভুক্ত করা হচ্ছে .......... যা এর অধীনে বিদ্যমান কমান্ডের যুক্তি (গুলি)


7

-আর পুনরাবৃত্তি জন্য, যা আলগাভাবে "বারবার" বলা যেতে পারে "

উদাহরণস্বরূপ এই কোডটি নিন:

───────────────────────────────────────────────────────────────────────────────
$ 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এর মধ্যে মধ্যবর্তী ডিরেক্টরিগুলিও।


যদি "ls -R" বারবার কিছু করতে থাকে তবে আপনি একই আউটপুট একাধিকবার পেয়ে যাবেন;) +1 treeযদিও। এটি একটি দুর্দান্ত সরঞ্জাম।
পোড

হ্যাঁ সাধারণ লোকের কথায় কণ্ঠস্বর। আমি মূলধারায় একটি শব্দ খুঁজে পাওয়ার চেষ্টা করছিলাম যাতে নন প্রোগ্রামার ধরণের পক্ষে বোঝা সহজ হয়। আমি আরও ভাল শব্দটি ভাবতে চেষ্টা করব বা পরে মুছব।
WinEunuuchs2Unix

5

এখানে একটি সহজ ব্যাখ্যা, এটি বোধগম্য কারণ কারণ যখন এটি উপ-ডিরেক্টরিগুলির বিষয়বস্তু প্রদর্শন করার কথা আসে, একই ফাংশনটি ইতিমধ্যে জানে যে কোনও ডিরেক্টরিতে কী করা উচিত। সুতরাং ফলাফলটি পেতে কেবল প্রতিটি উপ-ডিরেক্টরিতে নিজেকে কল করা দরকার!

সিউডোকোডে এটি দেখতে এরকম কিছু দেখাচ্ছে:

recursive_ls(dir)
    print(files and directories)
    foreach (directoriy in dir)
        recursive_ls(directory)
    end foreach
end recursive_ls
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.