Mengapa cd bukan program?

129

Saya selalu bertanya-tanya mengapa cdbukan program, tetapi tidak pernah berhasil menemukan jawabannya.

Adakah yang tahu mengapa ini masalahnya?

AkshaiShah
sumber
1
Saya ingat membaca (saya tidak dapat menemukan di mana) bahwa cdperintah unix yang asli adalah program yang terpisah. Shell itu menanganinya secara khusus karena tidak fork, hanya saja exec. Dan ketika cdselesai, itu akan eksekutif sh. Saya tidak tahu apakah ini kisah nyata.
camh
Apa gunanya? Jika itu akan menambahkan penanganan khusus, mungkin juga hanya memanggil chdirsyscall. sumber: v1 v5 v7 (versi pertama dengan shell Bourne)
Mikel
2
@camh, ini adalah kisah nyata. Saya telah membaca itu juga dalam sebuah artikel yang ditulis oleh Dennis M. Ritchie, “Evolusi Sistem Pembagian Waktu Unix”, Jurnal Teknis AT&T Bell Laboratories 63 (6), Bagian 2, Oktober 1984.
jlliagre
@Mikel: Saya setuju itu tidak ada gunanya, tapi saya hanya menyampaikan cerita tentang cdyang saya baca. Saya jelas salah tentang aspek itu, sekarang @jlliagre telah mengisi detailnya.
camh

Jawaban:

172

The cdperintah memodifikasi "direktori kerja saat ini", kan?

"direktori kerja saat ini" adalah properti yang unik untuk setiap proses.

Jadi, jika cditu sebuah program, ia akan bekerja seperti ini:

  1. cd foo
  2. yang cdproses dimulai
  3. yang cdproses mengubah direktori untuk proses cd
  4. yang cdkeluar proses
  5. shell Anda masih memiliki keadaan yang sama, termasuk direktori kerja saat ini, yang ia lakukan sebelum Anda mulai.
Daniel Pittman
sumber
8
Lima langkah Anda sudah benar, tetapi "jika cdsuatu program itu akan bekerja seperti ini" harus "ketika cddigunakan dalam implementasi program eksternal, itu berfungsi seperti ini".
jlliagre
1
Tidak menjadi programmer sistem, juga tidak benar-benar memiliki pengetahuan mendalam tentang seluk beluk berinteraksi dengan shell, saya akan mengharapkan shell untuk mengekspos direktori kerjanya saat ini, dan cd menjadi program yang mengakses dan mengubah properti itu. Memahami, setelah melihat jawaban ini, bahwa itu mungkin kurang optimal dengan cara kerjanya karena berbagai alasan.
Jason
108

cdselain menjadi builtin shell, sebenarnya juga merupakan program pada OS yang kompatibel dengan POSIX. Mereka harus menyediakan executable independen untuk utilitas reguler, seperti cd. Hal ini misalnya kasus dengan Solaris , AIX , HP-UX dan OS X .

Jelas, builtin cdmasih wajib karena implementasi eksternal tidak mengubah direktori shell saat ini. Namun, yang terakhir masih bisa bermanfaat. Berikut adalah contoh yang menunjukkan bagaimana POSIX membayangkan bagaimana cdperintah ini dapat digunakan:

find . -type d -exec cd {} \;

Pada sistem POSIX, oneliner ini akan melaporkan pesan kesalahan untuk semua direktori yang tidak diizinkan cdmasuk. Pada sebagian besar distribusi Gnu / Linux, gagal dengan pesan kesalahan itu:

find: `cd': No such file or directory

Dan inilah jawaban untuk pertanyaan Anda, " Mengapa cd bukan program? " Oleh salah satu penulis Unix yang asli. Pada implementasi Unix yang sangat awal, cd(dieja chdirpada waktu itu) adalah program eksternal. Itu hanya berhenti bekerja secara tak terduga setelah forkpertama kali diterapkan.

Mengutip Dennis Ritchie :

Di tengah kegembiraan kami, ditemukan bahwa perintah chdir (ubah direktori saat ini) telah berhenti bekerja. Ada banyak membaca kode dan introspeksi cemas tentang bagaimana penambahan garpu bisa mematahkan panggilan chdir. Akhirnya kebenaran muncul: dalam sistem lama chdir adalah perintah biasa; itu menyesuaikan direktori saat ini dari proses (unik) yang melekat pada terminal. Di bawah sistem baru, perintah chdir dengan benar mengubah direktori saat ini dari proses yang dibuat untuk menjalankannya, tetapi proses ini segera dihentikan dan tidak memiliki efek apa pun pada shell induknya! Itu perlu untuk membuat chdir perintah khusus, dijalankan secara internal di dalam shell. Ternyata beberapa fungsi mirip perintah memiliki properti yang sama, misalnya masuk.

Sumber: Dennis M. Ritchie, " Evolusi Sistem Pembagian Waktu Unix ", Jurnal Teknis AT&T Bell 63 (6), Bagian 2, Oktober 1984, hal.1577–93

Unix Version 1 (Maret 1971) halaman manual chdir menyatakan:

Karena proses baru dibuat untuk mengeksekusi setiap perintah, chdir tidak akan efektif jika ditulis sebagai perintah normal. Karena itu diakui dan dieksekusi oleh Shell.

Jlliagre
sumber
10
... jadi, tampaknya, POSIX mengamanatkan bahwa akan ada yang dapat cddieksekusi independen , tetapi itu tidak akan melakukan apa-apa (kecuali mungkin memancarkan pesan kesalahan jika dipanggil dengan argumen yang salah). Aneh.
Ilmari Karonen
4
Oh well, jika itu benar, itu tidak akan menjadi hal paling bodoh di POSIX.
Kaz
5
The POSIX Halaman cd juga mengatakan "Sejak cd mempengaruhi lingkungan eksekusi shell saat ini, selalu disediakan sebagai shell biasa built-in.".
Mikel
6
@ Ka, mereka bukan hal yang sama sekali berbeda. Mereka melakukan hal yang sama tetapi hanya yang builtin yang mempengaruhi shell saat ini.
jlliagre
13
@ Ka: Tolong jangan panggil aku konyol sementara aku hanya melaporkan fakta. Anda mungkin setuju atau tidak setuju dengan POSIX tetapi tidak menembak pengirim pesan.
jlliagre
47

Dari pengantar Bash ( Apa itu shell? ):

Shells juga menyediakan seperangkat kecil perintah bawaan (builtin) yang mengimplementasikan fungsionalitas yang tidak mungkin atau tidak nyaman untuk didapatkan melalui utilitas terpisah. Sebagai contoh, cd, break, continue, dan exec) tidak dapat dilaksanakan di luar shell karena mereka secara langsung memanipulasi shell itu sendiri. The history, getopts, kill, atau pwdbuiltin, antara lain, bisa diimplementasikan dalam utilitas terpisah, tetapi mereka lebih nyaman untuk digunakan perintah sebagai builtin. Semua builtin shell dijelaskan di bagian selanjutnya.

cjc
sumber
29

Untuk April Mop tahun ini, saya menulis versi mandiricd .

Tidak ada yang punya lelucon. Mendesah.

Siapa pun yang tidak yakin bahwa itu cdharus dibangun ke dalam shell harus mengunduhnya, membangunnya, dan mencobanya.

Baca halaman manualnya juga. :)

Warren Young
sumber
Kode yang sangat berguna! :-)
dschulz
6
Baik Anda melihat seseorang bekerja untuk membuat Gnu / Linux lebih sesuai dengan POSIX. Implementasi Anda bukan hanya lelucon yang bagus, tetapi sebenarnya sesuatu yang hilang dari distribusi Linux ...
jlliagre
8
Saya pikir saya akan mencoba lagi tahun depan, mengutip masalah POSIX. ;)
Warren Young
6 tahun kemudian: Ya kan?
Peter A. Schneider
@ PeterA.Schneider: Saya pikir sudah jelas bahwa saya bercanda, jadi untuk menjadi jelas, tidak, saya tidak benar-benar akan mengeluarkan banyak upaya untuk memasukkan ini ke dalam OS dan proyek-proyek seperti OS seperti Cygwin yang saat ini kekurangan /bin/cd. Jika Anda ingin mengambil kode saya dan menjadikannya pencarian pribadi Anda, Anda dapat melakukannya.
Warren Young
4

The cdperintah dalam shell tidak bisa menjadi proses yang terpisah karena dalam Unix tidak ada mekanisme untuk mengubah direktori kerja saat ini proses yang berbeda (bahkan tidak proses induk).

Jika cdproses yang berbeda maka harus mengubah direktori kerja saat ini dari induknya (shell) yang tidak mungkin di Unix. Sebaliknya cdadalah perintah built-in khusus. Shell memanggil fungsi-fungsi seperti chdir()dan fchdir() mengubah direktori kerjanya sendiri saat ini.

Catatan: kernel menyimpan nomor inode dari direktori kerja saat ini untuk setiap proses. Proses anak mewarisinya cwddari orang tuanya.

saurav1405
sumber
0

cd adalah perintah built-in shell. Semudah ini. Pria itu mengatakan semuanya. perintah cd mengubah direktori kerja untuk semua penerjemah dan (dalam lingkungan berulir) semua utas.


sumber
Karena shell adalah lingkungan yang menjaga dir Anda saat ini bekerja ($ PDW ...) atau cdable_vars. Builtin ini pada akhirnya adalah cara semua perintah yang terlihat oleh pengguna harus mengubah direktori kerja saat ini. Anda dapat mengujinya seperti itu: kompilasi bash tanpa cd.c dan cobalah untuk menulis skrip cd Anda sendiri, yang mencoba untuk menjaga semua lingkungan cdable_vars. Pertanyaan ini juga lebih terkait dengan pengembang. Saya yakin mereka bisa menjawab pertanyaan ini dengan lebih detail.
2
Ada alasan teknis yang sangat baik yang cdada di dalamnya. Saya sarankan Anda membaca jawaban dengan peringkat tertinggi dan mempertimbangkan bagaimana jawaban Anda dapat ditingkatkan.
Thorbjørn Ravn Andersen
Jawaban berperingkat tertinggi adalah yang terburuk yang pernah saya baca! Tapi ya Siapa saya!
3
Tapi itu menjawab pertanyaan mengapa .
Thorbjørn Ravn Andersen
-1

Saya pikir satu hal yang hilang dalam jawaban orang adalah bahwa direktori saat ini adalah variabel lingkungan yang dapat diubah setiap program. Jika Anda menggunakan perintah 'ekspor' untuk melihat daftar variabel lingkungan Anda saat ini, Anda akan memiliki:

declare -x PWD="/home/erfan"

dalam hasil Anda. Jadi dengan perintah 'cd' kami hanya ingin memodifikasi variabel internal ini. Saya pikir jika kita mencoba, kita bisa mengejar variabel PWD dari setiap pty di shell, tentu saja. Suka:

cder    #change current PTY $PWD variable

Tapi saya pikir tidak perlu dalam kasus normal. Dengan kata lain, kami mengambil bantuan dari bash (atau shell apa pun) untuk memodifikasi variabel internal yang ditentukan.

Erfankam
sumber
3
Meskipun memang benar bahwa Bourne shell mengekspos direktori kerja saat ini (CWD) sebagai $ PWD, itu bukan lokasi penyimpanan utama; lokasi aktual berada dalam struktur per-proses kernel. Oleh karena itu tidak benar untuk mengatakan bahwa CWD "adalah variabel lingkungan." Jika berhasil seperti yang Anda sarankan, C dua-liner ini akan mencetak ..jalur, bukan jalur tempat Anda memulainya: #include <stdlib.h> int main(void) { chdir(".."); puts(getenv("PWD")); }(Kerang C mengekspos CWD sebagai% cwd, omong-omong.)
Warren Young
mari tambahkan beberapa baris lain ke aplikasi Anda. #include <stdlib.h> int main (void) {chdir (".."); menempatkan (getenv ("PWD")); setenv (P "PWD", "/", 1); menempatkan (getenv ("PWD")); } Apa yang akan kita miliki sebagai hasil?
Erfankam
3
Itu hanya akan menimpa nilai variabel, tanpa efek samping pada CWD. Ini adalah tes yang lebih baik untuk menunjukkan bahwa: #include <unistd.h> int main(void) { char ac[99]; setenv("PWD", "/", 1); puts(getcwd(ac, sizeof(ac))); }Ini akan menunjukkan direktori tempat Anda memulai program, bukan /.
Warren Young
Saya pikir setiap proses memiliki direktori kerja dan variabel path juga. Jadi, Anda dengan chdir hanya mengubah atribut proses ini. Shell juga memiliki atribut ini dan dengan cd kami memodifikasi attribure ini.
Erfankam
4
Tidak, saya katakan bahwa itu $PWDhanya berarti bagi kulit Bourne. Ini hanya cara bagi shell untuk mengkomunikasikan sesuatu yang diketahuinya ke shell script sehingga mereka tidak perlu menelepon pwduntuk menemukannya. Setiap program mandiri tergantung pada nilai $PWDakan tidak dapat diandalkan.
Warren Young