Apa yang sebenarnya dilakukan `\ time`,` t \ ime` dan `\ cd`? (Bersenang-senang dengan garis miring terbalik di kulit kerang)

9

Saat mendiskusikan perbedaan antara /usr/bin/timeshell dan bash (bash dan zsh) bawaan time, seseorang menyebutkan bahwa seseorang dapat menggunakan \timesteno untuk mendapatkan /usr/bin/time.

Pertama tampaknya seperti jalan pintas yang tidak bersalah, tetapi kemudian beberapa pertanyaan muncul:

  • Kenapa juga t\imebekerja?
  • Mengapa \cdmengubah direktori, meskipun /usr/bin/cd¹ tidak?

Jadi jelas, \footidak setara dengan $(which foo). Pertanyaannya sekarang:

Apakah perilaku yang diamati \foopada bash dan zsh dengan cara apa pun dicakup oleh definisi POSIX tentang shell, dan jika demikian, mengapa berperilaku seperti itu?


Catatan kaki 1: /usr/bin/cdadalah, di sistem saya,

#!/bin/sh
builtin cd "$@"
Jonas Schäfer
sumber
Juga lihat unix.stackexchange.com/questions/12762/... Perhatikan bahwa \ perintah secara khusus didokumentasikan fungsionalitas tcsh yang mengatakan untuk mengabaikan alias untuk perintah.
Pengguna sederhana

Jawaban:

14

t\imeatau \cd(atau "tim"eatau 'cd'atau ${-##*}timeatau ${-+time}dan setiap kombinasi lain dari mengutip dan ekspansi Anda bisa memikirkan yang akhirnya akan memutuskan untuk timeatau cd), adalah bahwa: cara lain untuk menulis cddan time.

Namun, itu akhirnya akan menyelesaikan cdatau timedi kemudian hari parsing dan interpretasi sintaksis shell. Secara khusus, itu terjadi lama setelah pengenalan kata kunci shell dan penggantian alias terjadi.

Jadi, pada saat shell adalah mencari kata kunci dalam bahasa, ia tidak mengakui ti\mesebagai timekata kunci shell. Jadi a:

ti\me echo test

akan dikenali oleh shell sebagai perintah sederhana sebagai lawan dari timekata kunci diikuti oleh perintah sederhana.

Maka tanda kutip ti\meakan diproses (di sini backslash mengutip mkarakter yang tidak perlu kutip, karakter kutip dihapus, Anda dapatkan time) dan time perintah akan dicari seperti perintah lain (dalam daftar builtin , fungsi dan file yang dapat dieksekusi $PATH. Kemungkinan besar akan ada di /bin/timesini)

Sebab cd, tidak ada cdkata kunci dalam bahasa shell, hanya cdperintah builtin (yang lebih diutamakan daripada Anda /usr/bin/cd). Namun, jika Anda mendefinisikan alias untuk cd(suka alias cd=pushd), sama lagi. Sebagai pengganti alias dilakukan sangat awal, sebelum penghapusan kutipan, jika Anda memiliki alias untuk cddan bukan untuk \cd(perhatikan bahwa tidak banyak shell mengizinkan alias dengan backslash di dalamnya), kemudian dengan menulis:

\cd dir

Anda memastikan cdalias Anda tidak diganti.

Singkatnya, mengutip nama perintah atau bagian dari itu mencegah dari yang dilihat sebagai kata kunci shell (kata kunci menjadi hal-hal seperti while, for, if, {... timeadalah kata kunci di beberapa kerang saja), dan melewati alias Anda mungkin memiliki untuk itu .

Namun itu tidak memaksa perintah untuk menyelesaikan file yang dapat dieksekusi $PATH, perintah masih dicari pertama di antara fungsi (yang dapat Anda kerjakan dengan melakukan command time cmd...) dan builtins (yang dapat Anda kerjakan dengan melakukan env time cmd..., meskipun saya tidak tahu tentang sebuah shell yang memiliki timeperintah builtin ).

Perhatikan bahwa mengutip juga dapat memiliki pengaruh pada perilaku builtin khusus dari typeset/ declare/ export/ local... keluarga di beberapa kerang. Lihat Apakah kutipan diperlukan untuk penugasan variabel lokal? untuk detail.

Stéphane Chazelas
sumber
Jadi, perbedaan antara timedan cdyang mengarah ke perbedaan dalam perilaku yang diamati adalah bahwa itu timeadalah kata kunci dan cdmerupakan perintah bawaan ?
Jonas Schäfer
1
@JonasWielicki, itu timeadalah kata kunci dan cdbukan itu. (dan jika Anda memiliki alias untuk cdatau time, itu akan menjadi masalah lain). Yang cddibangun atau tidak tidak memiliki insiden pada titik ini (sejauh pengaruh kutipan berkaitan). Namun beberapa shell memiliki beberapa builtin yang berada di antara kata kunci dan builtin karena penguraiannya dilakukan secara berbeda dari builtin lainnya. Itu adalah kasus export/ typeset/ declare. Saya mungkin harus menambahkan beberapa catatan tentang hal ini dalam jawaban ini.
Stéphane Chazelas