Mengapa "ls" memerlukan proses terpisah untuk mengeksekusi?

14

Mengapa lsmembutuhkan proses terpisah untuk pelaksanaannya? Saya tahu alasan mengapa perintah suka cdtidak bisa dijalankan dengan mekanisme forking tetapi apakah ada salahnya jika lsdieksekusi tanpa forking?

crisron
sumber
1
Meskipun lsmerupakan program eksternal, echo *atau echo * .*(tergantung pada opsi shell) melakukan pekerjaan yang cukup baik dari daftar file tanpa forking.
gerrit
Ini bahkan lebih baik: printf "% s \ n" *
Costa
Catatan keanekaragaman shell: tcsh memiliki builtin ls-Fyang bertindak seperti ls -F. Itu ada untuk efisiensi. Anda selalu mendapatkan -Fide yang biasanya bagus. Jika Anda menentukan opsi lain, ia akan menjalankan perintah eksternal.

Jawaban:

18

Jawabannya kurang lebih itu lsadalah eksekusi eksternal. Anda dapat melihat lokasinya dengan menjalankan type -p ls.

Mengapa tidak lsdibangun ke dalam shell? Nah, mengapa harus begitu? Tugas shell bukanlah untuk mencakup setiap perintah yang tersedia, tetapi untuk menyediakan lingkungan yang mampu menjalankannya. Beberapa shell modern memiliki echo, printfdan sejenisnya sebagai builtin, yang secara teknis tidak harus builtin, tetapi dibuat untuk alasan kinerja ketika dijalankan berulang kali (terutama dalam loop ketat). Tanpa membuat mereka builtin, shell harus memotong dan mengeksekusi proses baru untuk setiap panggilan kepada mereka, yang bisa sangat lambat.

Paling tidak, menjalankan ls, executable eksternal, membutuhkan menjalankan salah satu keluarga panggilan sistem exec. Anda bisa melakukan ini tanpa forking, tetapi itu akan menggantikan shell utama yang Anda gunakan. Anda dapat melihat apa yang terjadi dalam contoh itu dengan melakukan hal berikut:

exec ls; echo "this never gets printed"

Karena gambar proses shell Anda diganti, shell saat ini tidak lagi dapat diakses setelah melakukan ini. Agar shell dapat terus berjalan setelah menjalankan ls, perintah tersebut harus dibangun ke dalam shell.

Forking memungkinkan penggantian proses yang bukan shell utama Anda, yang berarti Anda dapat terus menjalankan shell Anda sesudahnya.

Chris Down
sumber
1
Saya pikir dia bertanya mengapa ls (1) bukan fitur built-in dari shell, yang seseorang harus jelaskan bagaimana vendor yang berbeda memiliki opsi yang berbeda untuk ls (1) dan dapat menanyakan hal-hal yang berbeda dari sistem file, dll. Dan juga naik, dan sebagian besar surut memilikinya 'dibangun' shell.
llua
@llua saya menambahkan beberapa informasi tentang itu, dan kasus-kasus pengecualian echo, printf, dll
Chris Bawah
Tidak selalu jelas mengapa beberapa hal dibangun dan yang lainnya tidak. Misalnya, mengapa cdtidak dapat dieksekusi eksternal?
Faheem Mitha
@FaheemMitha Ada adalah sebuah eksternal cddieksekusi dalam sistem operasi POSIX-compliant ( lihat di sini ). Jika Anda ingin benar-benar chdir () dalam proses saat ini, Anda harus memasukkannya ke dalam shell.
Chris Down
sudah menjadi kebiasaan mengapa lsitu eksternal, tetapi bisa juga diimplementasikan dalam sebuah shell. Lihat busybox.
15

The Bash Reference Manual negara:

Perintah builtin diperlukan untuk mengimplementasikan fungsionalitas yang tidak mungkin atau tidak nyaman untuk didapatkan dengan utilitas terpisah.

Artinya, shell dirancang hanya untuk menyertakan perintah bawaan jika:

  1. Diperlukan oleh standar POSIX
  2. Perintah yang memerlukan akses ke shell itu sendiri, seperti built-in control pekerjaan
  3. Perintah yang sangat sederhana, tidak tergantung pada OS dan meningkatkan efisiensi eksekusi ketika diimplementasikan sebagai built-in, seperti printf

The lsperintah tidak sesuai salah satu syarat-syarat di atas.

Namun , tidak ada kendala pemrograman yang akan mencegah ls diimplementasikan sebagai built-in, yang mengeksekusi dalam proses yang sama dengan penerjemah bash. Alasan desain untuk perintah yang tidak diimplementasikan sebagai built-in shell adalah:

  1. Shell harus terpisah dari sistem file - tidak ada perintah bawaan yang harus bergantung pada operasi sistem file atau perangkat periferal yang benar
  2. Perintah yang mungkin tipe sistem file atau OS tergantung harus dieksekusi terpisah
  3. Perintah yang Anda mungkin ingin pipa ke atau dari harus proses terpisah
  4. Perintah yang mungkin ingin Anda jalankan di latar belakang harus dieksekusi terpisah
  5. Perintah yang memiliki sejumlah besar kemungkinan parameter lebih baik diimplementasikan dalam executable terpisah
  6. Perintah yang harus memiliki output yang sama, terlepas dari jenis shell (bash, csh, tsh, ...) memanggil mereka harus executable yang berdiri sendiri

Mengenai alasan pertama - Anda ingin shell menjadi independen dan sekuat mungkin. Anda tidak ingin shell terjebak pada lsmount NFS yang "tidak merespons masih mencoba".

Mengenai alasan kedua - Dalam banyak kasus Anda mungkin ingin menggunakan shell untuk sistem yang menggunakan Busybox atau sistem file lain yang memiliki lsimplementasi yang berbeda . Atau bahkan menggunakan sumber shell yang sama di OS yang memiliki lsimplementasi yang berbeda .

Mengenai alasan ketiga - Untuk ekspresi seperti find . -type d | xargs ls -laditu akan sulit atau tidak mungkin untuk menerapkan lsdalam proses yang sama dengan shell interpreter.

Mengenai alasan keempat - Beberapa lsperintah bisa memakan waktu lama untuk diselesaikan. Anda mungkin ingin shell terus melakukan sesuatu yang lain sementara itu.


Catatan: Lihat posting bermanfaat ini oleh Warren Young dalam menanggapi pertanyaan serupa.

Jonathan Ben-Avraham
sumber
Anda melewatkan kemudahan pemipaan output jika itu perintah terpisah, dan semua pemrograman yang diperlukan untuk menyalurkan shell primitive ke executable terpisah.
Bruce Ediger
@BruceEdiger: Senang menerima komentar dari BE yang terhormat. Terima kasih! Saya percaya bahwa alasan 3 mencakup komentar Anda, bukan?
Jonathan Ben-Avraham
1
Saya berpikir lebih dalam tentang betapa rumitnya kode sumber shell itu sendiri jika harus menangani pipa untuk proses eksternal, dan menyalurkan output dari perintah internal seperti hipotesis lske dalam proses eksternal. Itu bisa dilakukan, tetapi itu akan rumit.
Bruce Ediger
1
Saya takut sebagian besar jika tidak semua 5 poin Anda diperdebatkan. 1: ls (semoga) independen dari implementasi sistem file. Terserah kernel untuk menyediakan antarmuka yang konsisten ke pustaka dan aplikasi standar. 2: ls cenderung kurang tergantung pada OS daripada shell. 3: kerang jelas memungkinkan builtin dalam pipa. 4: shell pasti memungkinkan builtin dijalankan di latar belakang. 5: itu cukup subjektif.
jlliagre
1
@ JonathanBen-Avraham @BruceEdiger Bukankah kerang sudah menangani kasing pipa untuk builtin dengan subkulit? misalnya bashkeluaran alias | grep ls. masukancat /etc/passwd | while read a; do echo "$a"; done
Matt
2

lstidak memerlukan proses terpisah. Sangat sedikit perintah yang benar-benar memerlukan proses terpisah: hanya yang perlu mengubah hak istimewa.

Sebagai aturan, shell mengimplementasikan perintah sebagai builtin hanya ketika perintah itu perlu diimplementasikan sebagai builtin. Perintah seperti alias, cd, exit, export,jobs , ... perlu untuk membaca atau memodifikasi beberapa keadaan internal dari shell, dan karena itu tidak dapat menjadi program terpisah. Perintah yang tidak memiliki persyaratan seperti itu dapat berupa perintah terpisah; dengan cara ini, mereka dapat dipanggil dari shell atau program lain.

Melihat daftar builtin di bash, hanya builtin berikut yang dapat diimplementasikan sebagai perintah terpisah. Bagi beberapa dari mereka, akan ada sedikit kehilangan fungsi.

  • command- tetapi itu akan kehilangan kegunaannya dalam situasi di mana PATHmungkin tidak diatur dengan benar dan script menggunakan commandsebagai bagian dari pengaturannya.
  • echo - Ini adalah builtin untuk efisiensi.
  • help - bisa menggunakan database terpisah, tetapi menanamkan teks bantuan di shell executable memiliki keuntungan membuat shell executable mandiri.
  • kill - ada dua keuntungan dalam memiliki builtin: ia dapat mengenali penunjukan pekerjaan selain ID proses, dan dapat digunakan bahkan ketika tidak ada sumber daya yang cukup untuk memulai proses terpisah.
  • printf- Untuk alasan yang sama seperti echo, dan juga untuk mendukung -vopsi untuk menempatkan output dalam variabel.
  • pwd - builtin menawarkan kemampuan tambahan untuk pelacakan direktori saat ini yang logis (membiarkan tautan simbolik tetap utuh alih-alih meluaskannya).
  • test- itu adalah builtin untuk efisiensi (dan bash juga melakukan sihir dengan file yang dipanggil /dev/fd/…pada beberapa sistem operasi)

Beberapa cangkang menawarkan sejumlah besar builtin tambahan. Ada sash , yang merupakan shell yang dirancang untuk menjadi biner mandiri untuk perbaikan darurat (ketika beberapa perintah eksternal mungkin tidak dapat digunakan). Ini memiliki built-in ls, disebut -ls, serta alat-alat lain seperti -grepdan -tar. Sash's builtin memiliki kemampuan lebih sedikit daripada perintah penuh. Zsh menawarkan beberapa builtin serupa dalam modul zsh / file-nya . Tidak ada ls, tetapi ekspansi wildcard ( echo *) dan zstatdapat melayani fungsi serupa.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
2

Saya pikir ada sesuatu yang orang hilang di sini adalah kompleksitas geser dari lsprogram GNU di Linux. Membandingkan ukuran executable lsto bashdan dashshell pada sistem Debian saya, kami melihat bahwa itu cukup besar:

graeme@graeme:~$ ls -lh /bin/{ls,bash,dash}
-rwxr-xr-x 1 root root 953K Mar 30  2013 /bin/bash
-rwxr-xr-x 1 root root 115K Dec 25 20:25 /bin/dash
-rwxr-xr-x 1 root root 108K Jul 20 22:52 /bin/ls

Termasuk lsfitur penuh sebagai versi GNU bashakan meningkatkan ukuran yang dapat dieksekusi sebesar 10%. Ukurannya hampir sama dengan dashcangkang penuh !

Sebagian besar shell builtin dipilih karena mereka berintegrasi dengan shell dengan cara yang tidak dapat dieksekusi oleh eksternal (pertanyaan menunjukkan cd, tetapi contoh lain adalah versi bash untuk killmengintegrasikan dengan kontrol bash job) atau karena mereka adalah perintah yang sangat sederhana untuk diimplementasikan, memberikan hasil besar kecepatan vs ukuran ( truedanfalse sesederhana yang didapat).

GNU lsmemiliki siklus pengembangan yang panjang dan mengimplementasikan opsi-opsi untuk menyesuaikan apa / bagaimana hasil ditampilkan. Menggunakan bawaan secara default akan kehilangan fungsionalitas ini atau secara signifikan meningkatkan kompleksitas dan ukuran shell.

Graeme
sumber
1

cddibangun ke dalam shell, lsadalah program terpisah yang akan Anda lihat /bin/ls.

DopeGhoti
sumber
0

Ini melakukan apa yang Anda cari:

printf "%s\n" *

Anda juga dapat menyimpan nama file dalam array:

files=(`printf "%s\n" *`)  #items are separated by whitespace
echo ${#files[*]} files
for index in ${!a[*]}
do printf "%d: %s\n" $index ${a[$index]};
done

Tapi itu tidak peduli tentang spasi dalam nama.
Ini berlaku untuk variabel dan peduli ruang:

printf "%s\n" * | while read a; do echo $a; done
Costa
sumber