Saya mengerti bahwa ls -R
menampilkan daftar direktori. Tetapi mengapa itu bersifat rekursif? Bagaimana rekursi digunakan dalam proses?
command-line
ls
Mint. K.
sumber
sumber
ls
menemukan direktori itu secara rekursif mendaftar direktori itu.Jawaban:
Pertama, mari kita tentukan struktur folder arbitrer:
Ketika kami melakukannya
ls
, kami mendapatkan output dari folder dasar saja:Namun, ketika kita menelepon
ls -R
, kita mendapatkan sesuatu yang berbeda:Seperti yang Anda lihat, itu berjalan
ls
di folder dasar, dan kemudian semua folder anak. Dan semua folder cucu, tak terhingga. Secara efektif, perintah akan melalui setiap folder secara rekursif hingga menyentuh akhir pohon direktori. Pada titik itu, muncul kembali cabang di pohon dan melakukan hal yang sama untuk setiap sub-folder, jika ada.Atau, dalam pseudo-code:
Dan karena saya bisa, referensi implementasi Java sama.
sumber
Sebenarnya, ada dua pertanyaan yang digabungkan erat yang mungkin Anda tanyakan.
ls
? Dari ungkapan Anda ("Bagaimana rekursi digunakan dalam proses?"), Saya pikir ini adalah bagian dari apa yang ingin Anda ketahui. Jawaban ini menjawab pertanyaan itu.Mengapa masuk akal untuk
ls
diimplementasikan dengan teknik rekursif:FOLDOC mendefinisikan rekursi sebagai:
Cara alami untuk mengimplementasikannya
ls
adalah dengan menulis fungsi yang membangun daftar entri sistem file yang akan ditampilkan, dan kode lain untuk memproses jalur dan argumen opsi dan untuk menampilkan entri yang diinginkan. Fungsi itu sangat mungkin diimplementasikan secara rekursif.Selama pemrosesan opsi,
ls
akan menentukan apakah telah diminta untuk beroperasi secara rekursif (dengan dipanggil dengan-R
bendera). Jika demikian, fungsi yang membangun daftar entri yang akan ditampilkan akan memanggil dirinya sendiri satu kali untuk setiap direktori yang dicantumkannya, kecuali.
dan..
. Mungkin ada versi rekursif dan non rekursif yang terpisah dari fungsi ini, atau fungsi dapat memeriksa setiap kali jika seharusnya beroperasi secara rekursif.Ubuntu
/bin/ls
, executable yang berjalan saat Anda menjalankanls
, disediakan oleh GNU Coreutils , dan memiliki banyak fitur. Akibatnya, kodenya agak lebih panjang dan lebih rumit dari yang Anda harapkan. Tetapi Ubuntu juga mengandung versi yang lebih sederhanals
, yang disediakan oleh BusyBox . Anda dapat menjalankan ini dengan mengetikbusybox ls
.Cara
busybox ls
menggunakan rekursi:ls
di BusyBox diimplementasikan dalamcoreutils/ls.c
. Ini berisiscan_and_display_dirs_recur()
fungsi yang dipanggil untuk mencetak pohon direktori secara rekursif:Garis di mana panggilan fungsi rekursif berlangsung adalah:
Melihat fungsi rekursif panggilan saat terjadi:
Anda dapat melihat ini beroperasi jika Anda menjalankan
busybox ls
debugger. Pertama instal simbol debug dengan mengaktifkan paket -dbgsym.ddeb dan kemudian instalbusybox-static-dbgsym
paket tersebut. Instalgdb
juga (itulah debugger).Saya sarankan debugging
coreutils ls
pada pohon direktori sederhana.Jika Anda tidak memiliki satu yang berguna, buat satu (ini bekerja dengan cara yang sama seperti
mkdir -p
perintah dalam jawaban WinEunuuchs2Unix ):Dan isi dengan beberapa file:
Anda dapat memverifikasi
busybox ls -R foo
pekerjaan seperti yang diharapkan, menghasilkan output ini:Buka
busybox
di debugger:GDB akan mencetak beberapa informasi tentang dirinya sendiri. Maka itu harus mengatakan sesuatu seperti:
(gdb)
adalah prompt Anda di debugger. Hal pertama yang harus Anda beri tahu GDB untuk dilakukan pada prompt ini adalah mengatur breakpoint di awalscan_and_display_dirs_recur()
fungsi:Saat Anda menjalankannya, GDB harus memberi tahu Anda sesuatu seperti:
Sekarang beri tahu GDB untuk menjalankan
busybox
dengan (atau nama direktori apa pun yang Anda inginkan) sebagai argumennya:ls -R foo
Anda mungkin melihat sesuatu seperti ini:
Jika Anda melihat
No such file or directory
, seperti di atas, tidak apa-apa. Tujuan dari demonstrasi ini adalah hanya untuk melihat kapanscan_and_display_dirs_recur()
fungsi telah dipanggil, jadi GDB tidak perlu memeriksa kode sumber yang sebenarnya.Perhatikan bahwa debugger mencapai breakpoint bahkan sebelum entri direktori dicetak. Rusak di entrace untuk fungsi itu, tapi kode dalam fungsi yang harus dijalankan untuk setiap direktori yang akan dicacah untuk mencetak.
Untuk memberi tahu GDB untuk melanjutkan, jalankan:
Setiap kali
scan_and_display_dirs_recur()
dipanggil, breakpoint akan dipukul lagi, sehingga Anda akan melihat rekursi beraksi. Sepertinya ini (termasuk(gdb)
prompt dan perintah Anda):Fungsi ini ada
recur
dalam namanya ... apakah BusyBox hanya menggunakannya ketika-R
bendera diberikan? Dalam debugger, ini mudah ditemukan:Bahkan tanpa
-R
, implementasi khusus inils
menggunakan fungsi yang sama untuk mencari tahu entri sistem file apa yang ada dan menunjukkannya.Saat Anda ingin keluar dari debugger, katakan saja:
Bagaimana
scan_and_display_dirs_recur()
tahu jika itu harus menyebut dirinya:Secara khusus bagaimana cara kerjanya berbeda ketika
-R
bendera dilewatkan? Memeriksa kode sumber (yang mungkin bukan versi yang tepat pada sistem Ubuntu Anda) mengungkapkan bahwa ia memeriksa struktur data internalG.all_fmt
, tempat ia menyimpan opsi apa yang telah dipanggil dengan:(Jika BusyBox telah dikompilasi tanpa dukungan untuk
-R
, maka BusyBox juga tidak akan mencoba menampilkan entri sistem file secara rekursif; itulahENABLE_FEATURE_LS_RECURSIVE
bagian dari itu.)Hanya ketika
G.all_fmt & DISP_RECURSIVE
benar kode yang berisi panggilan fungsi rekursif dijalankan.Jika tidak, fungsi hanya berjalan sekali (per direktori ditentukan pada baris perintah).
sumber
Ketika Anda memikirkannya, "rekursif" masuk akal untuk perintah yang bekerja pada direktori dan file dan direktori mereka serta file dan direktori mereka serta file dan direktori serta file mereka .........
.... sampai seluruh pohon dari titik yang ditentukan turun telah dioperasikan oleh perintah, dalam hal ini daftar isi setiap subdirektori dari setiap subdirektori dari setiap subdirektori .......... yang ada di bawah argumen dari perintah
sumber
-R adalah untuk rekursi, yang secara longgar dapat disebut "berulang kali".
Ambil kode ini misalnya:
The
-p
dalam membuat direktori memungkinkan Anda untuk massa membuat direktori dengan satu perintah. Jika satu atau lebih direktori menengah atas sudah ada, itu bukan kesalahan dan direktori menengah bawah dibuat.Kemudian
ls -R
daftar secara rekursif setiap direktori tunggal dimulai dengan temp dan bekerja dengan cara menuruni pohon ke semua cabang.Sekarang mari kita lihat pelengkap
ls -R
perintah, yaitutree
perintah:Seperti yang Anda lihat,
tree
hasil yang sama denganls -R
kecuali lebih ringkas dan berani saya katakan "lebih cantik".Sekarang mari kita lihat cara menghapus direktori yang baru saja kita buat dalam satu perintah sederhana:
Ini secara rekursif menghapus
temp
dan semua sub-direktori di bawahnya. yaitutemp/a
,temp/b/1
dantemp/c/1/2
ditambah direktori tengah di antaranya.sumber
tree
. Ini alat yang hebat.Inilah penjelasan sederhana, masuk akal karena ketika datang untuk menampilkan isi subdirektori, fungsi yang sama sudah tahu apa yang harus dilakukan dengan direktori. Oleh karena itu hanya perlu memanggil dirinya sendiri pada setiap subdirektori untuk mendapatkan hasil itu!
Dalam pseudocode terlihat seperti ini:
sumber