Pertanyaan Mengapa perintah `which` tidak berfungsi untuk` cd`? Saya tidak dapat menemukan executable untuk `cd` baik!


Saya mencoba which cd dan itu tidak memberi jalan tetapi malah mengembalikan kode keluar 1 (diperiksa dengan echo $?). The coreutil cd itu sendiri berfungsi, jadi eksekutabel seharusnya ada di sana, kan? Saya juga berlari find untuk cd, tetapi tidak ada file yang dapat dieksekusi yang ditampilkan. Bagaimana cara menerapkannya?

Memperbarui:

Saya tidak tahu apakah saya harus menanyakan ini di postingan lain tetapi karena saya pikir itu baik di sini, saya memperluas (?) Posting ... Jadi jawabannya sebenarnya cukup sederhana, tidak ada eksekusi untuk itu - karena builtin - Tapi saya telah menemukan beberapa builtins (bash shell di Fedora) memiliki file yang dapat dieksekusi! Jadi builtin -> tidak ada eksekusi tidak benar saya kira? Mungkin jawaban yang menjelaskan apa sebenarnya builtins (perintah builtin?), Yang sebenarnya adalah masalah di sini, daripada lebih berfokus pada cd... Beberapa tautan bagus yang diposting sebelumnya menunjukkan bahwa builtins bukan program ... jadi apa itu? Bagaimana mereka bekerja? Apakah itu hanya fungsi atau utas cangkang?


28
2017-10-06 11:23


asal


Baca baca ini menjawab. Disarankan untuk digunakan type perintah - c0rp
Lihat Tanya Jawab ini tentang alasannya cd perlu dibangun: Mengapa cd bukan program? dan yang satu ini kenapa type lebih baik dari which: Kenapa tidak menggunakan "yang"? Apa yang harus digunakan? - terdon♦
Pertanyaan serupa di sini: askubuntu.com/q/613470/178596 - Wilf


Jawaban:


Perintah cd tidak bisa dieksekusi

Dalam cangkang, cd digunakan untuk "masuk ke direktori lain", atau lebih formal, untuk mengubah direktori kerja saat ini (CWD). Tidak mungkin untuk mengimplementasikannya sebagai perintah eksternal:

Direktori itu milik suatu proses

Direktori kerja saat ini adalah direktori yang digunakan untuk menafsirkan jalur relatif untuk mendapatkan jalur lengkap yang dapat digunakan untuk mengakses file. Jalur relatif digunakan di banyak tempat, dan interpretasi dalam satu proses tidak boleh mempengaruhi proses lain.
Untuk alasan ini, setiap proses memiliki direktori kerja saat ini.

cd adalah tentang mengubah direktori kerja saat ini dari proses shell, misalnya bash.

Jika itu adalah perintah eksternal, yang dapat dieksekusi di jalan, menjalankan yang dapat dijalankan akan membuat proses dengan direktori kerjanya sendiri, tanpa mempengaruhi yang ada pada shell saat ini. Bahkan jika perintah eksternal akan mengubah direktori itu, perubahan itu hilang ketika proses eksternal keluar.

Perintah shell builtin

Jadi tidak masuk akal untuk menjalankan perintah eksternal untuk tugas cd. Perintah cd perlu menerapkan perubahan ke proses shell yang sedang berjalan.

Untuk melakukan itu, itu adalah "perintah builtin" dari shell.

Perintah builtin adalah perintah yang berperilaku mirip dengan perintah eksternal, tetapi diimplementasikan dalam shell (jadi cd bukan bagian dari coreutils). Ini memungkinkan perintah untuk mengubah keadaan cangkang itu sendiri, dalam hal ini untuk memanggil chdir() Lihat lihat man 2 chdir);

Tentang which

Sekarang, jawaban atas pertanyaan judul itu mudah:
Perintah dieksekusi which tidak dapat memberi tahu kami bahwa cd adalah perintah bawaan karena perintah yang dapat dijalankan tidak tahu apa-apa tentang builtins.

Alternatif type -a

Sebagai alternatif untuk which, Kamu dapat memakai type -a; Dapat melihat perintah dan built-in yang dapat dieksekusi; Selain itu, ia melihat alias dan fungsi - juga diimplementasikan dalam shell:

$ type -a cd
cd is a shell builtin
$ type -a type
type is a shell builtin
$ type -a which
which is /usr/bin/which
which is /bin/which

45
2017-10-06 12:11



Penjelasan hebat! - SaltyNuts
Jauh lebih baik daripada jawaban yang diterima saat ini - ini menjelaskan Mengapa  cd adalah shell builtin. - ikdc


cdadalah POSIX-mandated shell builtin:

Jika perintah sederhana menghasilkan nama perintah dan daftar argumen opsional, tindakan berikut harus dilakukan:

  1. Jika nama perintah tidak mengandung garis miring, langkah pertama yang berhasil dalam urutan berikut akan terjadi:
      ...      
    • Jika nama perintah cocok dengan nama utilitas yang tercantum dalam tabel berikut, utilitas itu harus dipanggil.
        ...
      cd
        ...
    • Jika tidak, perintah harus dicari untuk menggunakan PATH ...

Sementara ini tidak secara eksplisit mengatakan itu harus built-in, spesifikasi selanjutnya mengatakan, dalam uraian tentang cd:

Karena cd mempengaruhi lingkungan eksekusi shell saat ini, ia selalu disediakan sebagai shell regular built-in.

Dari bash manual:

Perintah-perintah shell builtin berikut diwariskan dari Bourne Shell. Perintah-perintah ini diimplementasikan sebagaimana ditentukan oleh standar POSIX.
  ...

cd
       cd [-L|[-P [-e]]] [directory]

Saya kira Anda bisa memikirkan arsitektur di mana cd tidak harus menjadi builtin. Namun, Anda harus melihat apa yang tersirat di dalamnya. Jika Anda menulis kode khusus di shell untuk melakukan sesuatu untuk beberapa perintah, Anda semakin dekat dengan memiliki builtin. Semakin banyak yang Anda lakukan, semakin baik untuk memiliki builtin.

Sebagai contoh, Anda bisa memiliki shell IPC untuk berkomunikasi dengan subproses, dan akan ada cd program yang akan memeriksa keberadaan direktori dan apakah Anda memiliki izin untuk mengaksesnya dan kemudian berkomunikasi dengan shell untuk memberitahukannya untuk mengubah direktori. Namun, Anda harus kemudian memeriksa apakah proses berkomunikasi dengan Anda adalah anak (atau membuat sarana komunikasi khusus dengan anak-anak saja, seperti deskriptor file khusus, memori bersama, dll.), Dan jika prosesnya sebenarnya menjalankan yang tepercaya cd program atau yang lain. Itu seluruh kaleng cacing.

Atau Anda bisa memiliki cd program yang membuat chdir system call, dan memulai shell baru dengan semua variabel lingkungan saat ini diterapkan pada shell baru, dan kemudian membunuh shell induknya (entah bagaimana) ketika selesai.1

Lebih buruk lagi, Anda bahkan bisa memiliki sistem di mana sebuah proses bisa mengubah lingkungan proses lain (saya pikir secara teknis Anda dapat melakukan ini dengan debugger). Namun sistem seperti itu akan sangat, sangat rentan.

Anda akan menemukan diri Anda menambahkan lebih banyak kode untuk mengamankan metode tersebut, dan itu jauh lebih mudah untuk membuatnya menjadi builtin.


Sesuatu yang dapat dieksekusi tidak mencegahnya menjadi builtin. Inti masalah:

echo dan test

echo dan test adalah utilitas yang dimandatkan oleh POSIX (/bin/echo dan /bin/test). Namun hampir setiap shell populer memiliki builtin echo dan test. Demikian pula, kill juga builtin yang tersedia sebagai program. Lainnya termasuk:

  • sleep (tidak seperti biasanya)
  • time
  • false
  • true
  • printf

Namun, ada beberapa kasus di mana perintah tidak dapat berupa apa pun kecuali builtin. Salah satunya adalah cd. Biasanya, jika path lengkap tidak ditentukan, dan nama perintah cocok dengan yang ada pada builtin, fungsi yang sesuai dengan perintah itu dipanggil. Bergantung pada shell, perilaku builtin dan eksekusi dapat berbeda (ini khususnya masalah untuk echo, yang memiliki perilaku yang sangat berbeda. Jika Anda ingin memastikan perilaku, lebih baik untuk memanggil executable menggunakan path lengkap, dan menetapkan variabel seperti POSIXLY_CORRECT (bahkan tidak ada jaminan nyata).

Secara teknis tidak ada yang mencegah Anda dari menyediakan OS yang juga shell dan memiliki setiap perintah sebagai builtin. Dekat dengan ujung ekstrim ini adalah monolitik BusyBox. BusyBox adalah biner tunggal, yang (tergantung pada nama yang disebut) dapat berperilaku sebagai salah satu lebih dari 240 program, termasuk Shell Almquist (ash). Jika Anda tidak disetel PATH saat menjalankan BusyBox ash, program yang tersedia di BusyBox masih dapat diakses oleh Anda tanpa menentukan PATH. Mereka hampir menjadi shell builtins, kecuali bahwa shell itu sendiri adalah semacam builtin untuk BusyBox.


Studi kasus: The Debian Almquist Shell (dash)

Jika Anda melihat dash source, thread eksekusi adalah sesuatu seperti ini (tentu saja, dengan fungsi tambahan yang terlibat ketika pipa dan hal-hal lain digunakan):

main → cmdloop → evaltree → evalcommand

evalcommand kemudian digunakan findcommand untuk menentukan apa perintahnya. Jika itu adalah builtin, kemudian:

 case CMDBUILTIN:
     if (spclbltin > 0 || argc == 0) {
         poplocalvars(1);
         if (execcmd && argc > 1)
             listsetvar(varlist.list, VEXPORT);
     }
     if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
         if (exception == EXERROR && spclbltin <= 0) {
             FORCEINTON;
             break;

cmdentry.u.cmdadalah struct (struct builtincmd), salah satu anggotanya adalah penunjuk fungsi, dengan tanda tangan khas main: (int, char **). Itu evalbltin panggilan fungsi (tergantung pada apakah builtin adalah eval perintah atau tidak) baik evalcmd, atau penunjuk fungsi ini. Fungsi sebenarnya didefinisikan dalam berbagai file sumber. echo, misalnya, adalah:

int
echocmd(int argc, char **argv)
{
    int nonl;

    nonl = *++argv ? equal(*argv, "-n") : 0;
    argv += nonl;

    do {
        int c;

        if (likely(*argv))
            nonl += print_escape_str("%s", NULL, NULL, *argv++);
        if (nonl > 0)
            break;

        c = *argv ? ' ' : '\n';
        out1c(c);
    } while (*argv);
    return 0;
}

Semua tautan ke kode sumber di bagian ini berbasis nomor baris, sehingga dapat berubah tanpa pemberitahuan.


1 Sistem POSIX memang memiliki cd dapat dieksekusi.


Catatan sampingan:

Ada banyak posting bagus di Unix & Linux yang berhubungan dengan perilaku shell. Khususnya:

 Jika Anda belum melihat pola dalam pertanyaan yang tercantum sejauh ini, hampir semuanya terlibat Stéphane Chazelas.


29
2017-10-06 11:30



Perhatikan bahwa Anda bisa mendapatkan cd bantu teks dengan help cd (Hal yang sama untuk semua perintah shell builtin) - Sylvain Pineau
@SylvainPineau meskipun saya telah menautkan ke manual bash, saran itu umumnya tidak berlaku untuk shell lain, seperti zsh. - muru
Memang help adalah bash builtin (untuk zsh, itu run-help cd) - Sylvain Pineau
Deskripsi terkait dari spesifikasi POSIX tidak secara eksplisit mengatakan itu cd harus sebagai shell built-in ... tetapi berdasarkan bagaimana properti proses dan transfernya berfungsi di UNIX cd sebagai shell built-in adalah satu-satunya implementasi langsung. Lihat balas Volker Siegel. - pabouk
@pabouk memang (itu menyebutnya sebagai utilitas), dan kemudian melanjutkan dengan mengatakan: "Karena cd mempengaruhi lingkungan eksekusi shell saat ini, itu selalu disediakan sebagai shell reguler built-in." - muru


Anda tidak dapat menemukan eksekusi untuk cd karena tidak ada.

cd adalah perintah internal shell Anda (mis. bash).


8
2017-10-06 11:26





dari man which:

yang mengembalikan path dari file (atau tautan) yang akan menjadi   dieksekusi di lingkungan saat ini, telah argumennya telah diberikan   sebagai perintah dalam shell ketat POSIX-conformant. Ini dilakukan oleh ini   mencari PATH untuk mengeksekusi file yang cocok dengan nama   argumen. Itu tidak mengikuti tautan simbolis.

Seperti yang bisa kita lihat dari deskripsi which, hanya memeriksa PATH. Jadi, jika Anda menerapkan beberapa bash function, itu tidak akan menunjukkan apa-apa. Lebih baik digunakan type perintah bersama which.

Misalnya di Ubuntu ls perintah aliased to ls --color=auto.

$ type ls
ls is aliased to `ls --color=auto'

$ which ls
/bin/ls

Dan jika Anda menerapkan fungsi tes hello:

$ function hello() { for i in {1,2,3}; do echo Hello $i;done }
$ which hello

which tidak menunjukkan apa-apa. Tapi type:

$ type hello
hello is a function
hello () 
{ 
    for i in {1,2,3};
    do
        echo Hello $i;
    done
}

Dalam kasus Anda:

$ type cd
cd is a shell builtin

Ini artinya itu cdadalah shell builtin, itu ada di dalam bash. Semua bash builtins yang dijelaskan dalam man bash, di bagian SHELL BUILTIN COMMANDS

SHELL BUILTIN COMMANDS
       Unless otherwise noted, each builtin command documented in this section
       as accepting options preceded by - accepts -- to signify the end of the
       options.   The  :, true, false, and test builtins do not accept options
       and do not treat -- specially.  The exit, logout, break, continue, let,
       and  shift builtins accept and process arguments beginning with - with‐
       out requiring --.  Other builtins that accept  arguments  but  are  not
       specified  as accepting options interpret arguments beginning with - as
       invalid options and require -- to prevent this interpretation.

7
2017-10-06 11:48



Mmmm, manwhich. - IQAndreas
Mungkin harus lebih ditekankan: Jangan gunakan which, gunakan type. - tripleee