- Perilaku terminal yang terasa oleh pengguna terbentuk dari gabungan sistem operasi, shell, emulator terminal, serta kebiasaan tiap program, dan kebiasaan ini ternyata lebih konsisten daripada yang dibayangkan
- POSIX terutama membahas interaksi antara emulator terminal, sistem operasi, dan shell, serta sebagian utilitas inti, tetapi tidak menetapkan sampai detail perilaku program seperti
htop
- Pola seperti
Ctrl-C, q, Ctrl-D, 16 warna ANSI, key binding readline, penonaktifan warna pada output pipe, serta makna stdin/stdout untuk - terus berulang
- Perilaku yang terasa seperti hukum alam sebenarnya harus diimplementasikan oleh program atau library input; contohnya keluar dengan
Ctrl-D di ipython dan penghentian pencarian dengan Ctrl-C di prompt-toolkit
- Saat membuat program terminal baru atau memahami perilaku suatu tool, lebih praktis melihat ekspektasi default dan pengecualiannya terlebih dahulu daripada berasumsi “apa pun bisa dilakukan”
Empat pihak yang membentuk perilaku terminal
- Hal-hal yang terjadi di terminal umumnya dapat dilihat sebagai hasil kerja bersama empat pihak
- sistem operasi
- shell
- emulator terminal
- program yang sedang berjalan, seperti
top, vim, cat
- Dalam kombinasi seperti bash, GNOME Terminal, dan Linux, tiga elemen pertama relatif sudah dikenal, dan sebagian perilaku distandardisasi oleh POSIX
- Program individual tampak seperti bisa melakukan apa saja, tetapi dalam pengalaman penggunaan nyata mereka bertindak dengan cara yang cukup konsisten
Standarnya sedikit, tetapi ada kebiasaan
- Hampir tidak ada standar nyata yang menetapkan perilaku program terminal secara menyeluruh
- Ada dua acuan yang mendekati
- POSIX: terutama membahas interaksi antara emulator terminal, sistem operasi, dan shell, serta juga menetapkan sebagian perilaku utilitas inti seperti
cp
- command line interface guidelines: panduan yang membahas kebiasaan antarmuka command line
- Aturan-aturan ini bukan resep yang wajib diikuti penulis program, melainkan lebih dekat ke kebiasaan teknis yang diamati selama 20 tahun memakai terminal
- Ada banyak pengecualian, dan pengecualian sering kali punya alasan yang masuk akal
Beberapa aturan harus diimplementasikan langsung oleh program
- Lokasi file konfigurasi, output
--help, serta cara menulis output biasa ke stdout dan error ke stderr adalah tanggung jawab program yang relatif jelas
- Sebaliknya, sebagian perilaku terlihat alami, tetapi sebenarnya harus ditangani langsung oleh program atau library input
- Perilaku keluar dari REPL dengan
Ctrl-D adalah contoh yang mewakili
cat tidak memerlukan implementasi khusus; dalam cooked mode, sistem operasi mengembalikan EOF
ipython mengimplementasikan penanganan Ctrl-D melalui kode prompt-toolkit
- Memahami tanggung jawab implementasi seperti ini membuat perbedaan kecil perilaku antarprogram menjadi tidak terlalu mengejutkan
Aturan 1: Program non-interaktif keluar dengan Ctrl-C
- Program non-interaktif umumnya keluar saat
Ctrl-C ditekan
- Sebab jika program tidak menetapkan handler sinyal
SIGINT, secara default ia akan keluar saat Ctrl-C
- Aturan ini tidak berlaku begitu saja untuk program interaktif seperti
python3, bc, less
- Dalam program interaktif,
Ctrl-C bisa menghentikan pekerjaan yang sedang berjalan, bukan keluar dari program
- Contohnya adalah pencarian di
less atau kode Python yang sedang berjalan di python3
- Library pemrosesan input prompt-toolkit yang digunakan
ipython memiliki kode untuk menghentikan pencarian dengan Ctrl-C
Aturan 2: TUI biasanya keluar dengan q
- Program TUI seperti
less dan htop biasanya keluar saat q ditekan
- Aturan ini tidak berlaku untuk program yang tidak terasa alami jika keluar dengan
q
Aturan 3: REPL keluar dengan Ctrl-D pada baris kosong
- REPL seperti
python3 dan ed biasanya keluar saat Ctrl-D ditekan pada baris kosong
- Jika menjalankan program seperti
cat dalam cooked mode, sistem operasi mengembalikan EOF untuk Ctrl-D pada baris kosong
sqlite3, python3, fish, bash, dan lainnya sebenarnya tidak memakai cooked mode, tetapi mengimplementasikan shortcut ini untuk meniru perilaku default
- Contoh implementasi dapat dilihat di dua tempat
- REPL Erlang adalah pengecualian yang tidak keluar dengan
Ctrl-D
Aturan 4: Tidak melampaui 16 warna dasar
- Program terminal pada umumnya jarang memakai warna di luar 16 warna ANSI dasar
- Menentukan warna hex secara langsung sangat mungkin berbenturan dengan warna latar pengguna
- Misalnya, teks
#EEEEEE hampir tidak terlihat di latar putih, tetapi bisa terlihat baik-baik saja di latar gelap
- Jika memakai 16 warna dasar, besar kemungkinan pengguna sudah mengatur warna di emulator terminal agar cocok dengan warna latarnya
- Cara ini juga mengurangi asumsi tentang warna yang didukung emulator terminal
- Ada pengecualian berupa editor teks
- Helix secara default memakai latar ungu yang bukan warna dasar ANSI
- Helix bukan program “inti”, dan diasumsikan pengguna yang tidak menyukai skema warnanya dapat mengganti tema
Aturan 5: Mendukung key binding readline sampai batas tertentu
- Jika masuk akal, hampir semua program mendukung key binding readline sampai batas tertentu
- Banyak program tidak memakai
readline secara langsung, tetapi meniru key binding bergaya emacs/readline
- Tidak semua program menirunya dengan cara yang persis sama
- atuin tampaknya memakai
Ctrl-A sebagai prefix, sehingga Ctrl-A tidak memindahkan kursor ke awal baris
- Program-program ini mengimplementasikan buffer cut-and-paste sendiri sehingga pengguna dapat menghapus baris dengan
Ctrl-U lalu menempelkannya dengan Ctrl-Y
- Ada juga pengecualian
- Program seperti
git, cat, nc tidak mendukung pengeditan baris kecuali backspace, Ctrl-W, dan Ctrl-U
- Editor teks memiliki cara pengeditan masing-masing
- Topik terkait dibahas lebih lanjut di entering text in the terminal is complicated
Aturan 5.1: Ctrl-W menghapus kata terakhir
- Di luar editor teks, saya belum pernah melihat program yang
Ctrl-W-nya tidak menghapus kata terakhir
- Dalam cooked mode, sistem operasi secara default menghapus kata terakhir saat
Ctrl-W ditekan, dan menghapus seluruh baris saat Ctrl-U ditekan
- Banyak program meniru perilaku default ini
- Saya tidak terpikir pengecualian selain editor teks
Aturan 6: Mematikan warna saat menulis ke pipe
- Sebagian besar program menonaktifkan warna saat target output adalah pipe
- Contoh
rg blah menyorot blah pada output terminal, tetapi mematikan sorotan saat output diarahkan ke pipe atau file
ls --color=auto memakai warna saat menulis ke terminal, dan tidak memakai warna saat menulis ke pipe
- Format juga dapat berubah tergantung apakah output diarahkan ke terminal
ls menyusun file dalam kolom pada output terminal
- ripgrep mengelompokkan match bersama judul
- Jika ingin memaksa warna terlihat,
unbuffer dapat membuat output program seolah-olah berupa tty
unbuffer rg blah | less -R
- Sebagian program dapat memaksa warna dengan flag
--color
- Contoh di atas juga dapat dilakukan dengan
rg --color=always | less -R
Aturan 7: - berarti stdin atau stdout
- Biasanya, jika
- diberikan sebagai pengganti nama file, program akan membaca dari stdin atau menulis ke stdout sesuai arah yang tepat
- Untuk memformat kode Python dari clipboard dengan
black lalu menyalinnya kembali, Anda bisa menjalankan perintah seperti berikut
pbpaste | black - | pbcopy
pbpaste adalah program Mac, dan di Linux pekerjaan serupa dapat dilakukan dengan xclip
- Sebagian besar program tampaknya mengimplementasikan cara ini ketika memang masuk akal, tetapi bisa saja ada banyak pengecualian
Mengapa butuh waktu lama untuk mempelajari aturan ini
- Aturan seperti ini biasanya tidak dipelajari secara eksplisit sekaligus, melainkan melalui beberapa tahap
- Pertama, Anda belajar bahwa ada aturan seperti “
Ctrl-C mengakhiri program”
- Anda menemukan pengecualian, misalnya
find berakhir tetapi less tidak
- Secara tidak sadar Anda menangkap pola bahwa pada program non-interaktif ia keluar, sedangkan pada program interaktif ia mungkin hanya menghentikan pekerjaan saat ini
- Baru kemudian Anda dapat merumuskannya sebagai aturan eksplisit
- Banyak pemahaman tentang terminal masih berada pada tahap pengenalan pola bawah sadar
- Menuliskan aturan-aturan ini dapat membantu orang lain mempelajari perilaku terminal sedikit lebih cepat
1 komentar
Pendapat Hacker News
Selain itu, program terminal harus menghormati warna latar depan/latar belakang default pengguna dan tidak mengubahnya tanpa alasan
Meski memakai warna, keluaran harus tetap bisa dibaca apa pun latar belakang/latar depan default dan palet warna terminalnya; jika makna disampaikan hanya lewat warna, makna itu akan hilang saat salin/tempel atau di terminal yang tidak mendukung warna
Emoji atau karakter non-ASCII yang tidak perlu juga harus digunakan dengan hati-hati, dan dalam bentuk output standar yang bergulir, sebaiknya jangan menghapus informasi penting seperti peringatan yang ditampilkan sementara atau nama file
Jika ingin memakai banyak warna mencolok dan animasi, setidaknya sediakan opsi pengaturan yang mudah dimatikan
Saya tidak tahu apakah akar penyebabnya sudah diperbaiki, tetapi itu membuat saya membuat PR workaround di beberapa proyek open source yang sedikit mengorbankan maksud artistik aslinya: https://github.com/docker-archive/toolbox/issues/695
Namun, warna kustom pengguna bisa disediakan
Ini lebih merupakan rangkuman hal-hal yang secara umum dapat diasumsikan sudah diikuti oleh semua program terminal
Belakangan ini sebagian penulis membuat tool dengan asumsi pengguna memakai font yang dipatch, sehingga sangat merusak kegunaan
Tulisan yang bagus
Karena disebutkan bahwa konvensi seperti ini sulit dipelajari, saya juga merekomendasikan Command Line Interface Guidelines, referensi favorit saya saat memikirkan CLI: https://clig.dev
Isinya mencakup aturan dari teks asli seperti keluar dengan Ctrl-C, menerima
-pada input standar, mematikan warna saat dipipe, dan masih banyak lagiDi dalamnya ada materi POSIX, GNU, Unix, panduan Heroku CLI, dan panduan aplikasi CLI 12-factor
Poin bahwa “output biasa harus ditulis ke stdout, error ke stderr” benar-benar penting
Output standar seharusnya menjadi tempat hanya untuk data yang diminta pengguna agar dibuat oleh program. Jika pengguna meminta data JSON, maka output standar harus berisi persis objek JSON itu saja, dan sama sekali tidak boleh ada hal lain
Nama standard error sebenarnya agak keliru; ini lebih mirip “stream pengguna standar” untuk mengirim semua pesan yang harus dibaca pengguna di terminal. Bukan hanya pesan error, tetapi juga pesan status dan output verbose termasuk di dalamnya
Dengan begitu, output program bisa dipipe ke program lain dengan mulus, sementara informasi yang bukan data tetap bisa menuju terminal atau dialihkan ke tempat lain
Akan bagus jika program bisa dengan mudah membuat file descriptor baru untuk koneksi terminal dengan tujuan tertentu, dan mendokumentasikan nomornya di manual seperti exit code. Demi kompatibilitas, default-nya bisa dikirim ke stdout atau stderr, dan saya berniat sedikit bereksperimen dengan ini
Ada 6 stream berbeda, dan masing-masing bisa dicegat secara terpisah atau dikonfigurasi berbeda: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_output_streams?view=powershell-7.4
greptidak akan bekerjaBeberapa tambahan: jika Anda baru pertama kali mendengar key binding readline/emacs seperti Ctrl-E dan Ctrl-W, perlu diketahui bahwa sebagian besar sumber input macOS menggunakan key binding ini
Jika memakai macOS, Anda bisa mencoba Ctrl-E, Ctrl-W, dan Ctrl-U di bilah alamat browser sekarang
Jika Anda memakai program command line yang sama sekali tidak mendukung pengeditan baris, Anda bisa memasang
rlwrapdan menjalankan REPL di bawahnya. Misalnya Standard ML of New Jersey memiliki REPL tetapi tidak punya fitur pengeditan baris, jadi bisa dilengkapi denganrlwrap smlnjUntuk pernyataan “jangan gunakan lebih dari 16 warna”, saya ingin melangkah lebih jauh: “jangan gunakan lebih dari 8 warna, atau setidaknya buat warnanya bisa dikonfigurasi.” Skema warna populer seperti Solarized dan Base 16 default terkadang memakai warna “terang” sebagai beberapa tingkat abu-abu, sehingga hijau terang yang dibayangkan penulis sebenarnya bisa tampil sebagai abu-abu yang sama dengan teks biasa
Emulator terminal yang saya gunakan, Alacritty, juga begitu, dan sebagian besar file explorer bertab juga berperilaku demikian. Seingat saya Windows Explorer sekarang juga seperti itu, tetapi sudah cukup lama saya tidak memakai Windows
Konvensi keluar dari REPL dengan Ctrl-D selalu membuat saya tersandung di GHCi
Biasanya saya menekan Ctrl-D, bingung karena tidak terjadi apa-apa, lalu teringat bahwa itu tidak berlaku di GHCi dan menjalankan
:qLalu Ctrl-D memasukkan karakter tak terlihat di awal input sehingga muncul error “lexical error at character '\EOT'”, dan saya harus mengetik
:qlagi tanpa prefiks tak terlihat itu agar GHCi keluarSaya bahkan tidak begitu tahu cara lainnya; apakah ada pengaturan yang mengubah perilaku ini?
Satu hal yang terlewat adalah perilaku memperlakukan
~sebagai direktori homeIni tampaknya bukan POSIX API, melainkan fitur shell. Di Go,
os.ReadFile("~/.bashrc")tidak berfungsi, tetapi di shellecho ~/~/~diperluas menjadi semacam/home/jrockway/~/~yourprogram ~/path/to/fileselalu berfungsi, tetapi bisa saja tidak di REPL yang menanyakan nama file. Dalam praktiknya, banyak perangkat lunak mendukung ini, jadi menurut saya layak dimasukkan ke “hal yang dilakukan sebagian besar program TUI”Dalam ekspansi kata, ekspansi tilde adalah langkah pertama, lalu diikuti pemecahan field, ekspansi pathname, dan penghapusan kutipan
Spesifikasi shell terkait ada di https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html#tag_19_06, dan spesifikasi lengkapnya dapat dilihat di https://pubs.opengroup.org/onlinepubs/9799919799/
Jika sebuah tool menambahkan ekspansi tilde, implementasinya menjadi rumit karena harus mengetahui direktori home pengguna saat ini, dan bisa muncul implementasi tidak lengkap seperti hanya mendukung
~tetapi bukan~nameDi shell POSIX,
~namediperluas menjadi direktori home pengguna tersebut, jadi harus bisa mencari direktori home pengguna arbitrer, termasuk pengguna sistem. Tergantung konfigurasi NSS, ini bisa jauh lebih rumit daripada membaca/etc/passwdUntuk TUI interaktif, mengimplementasikan ekspansi tilde bisa berguna, tetapi dalam kasus itu harus selengkap shell. Program CLI sebaiknya tidak melakukan ekspansi ajaib seperti ini
Akan muncul masalah seperti apa yang harus dilakukan jika ada file bernama
"~", bagaimana dengan"~username", bagaimana melakukan escape/quote, apa yang terjadi jika$HOMEtidak ada atau berbeda dari home sebenarnya, dan bagaimana di WindowsFakta yang kurang dikenal: di ssh, jika setelah baris baru Anda mengetik
"~.", klien akan memaksa koneksi ditutup dan server tidak bisa melakukan apa-apa, jadi sebaiknya jangan memasukkannya ke workflow./myprogram --config=~/.config/myprogramTentu saja banyak parser flag bisa memakai bentuk yang diperluas oleh shell, yaitu
./myprogram --config ~/.config/myprogram, jadi mereka mengetahuinya atau kebetulan mendukungnyaTetapi karena muscle memory, saya pasti mengetik
=. Sepertinya kebiasaan dari pustaka parsing flag di tempat kerja lama, dan karena alasan yang sama saya juga selalu memakai--underscores_like_thisalih-alih--hyphens-like-normal-peopleTerutama karena
..ditangani di level OS API, wajar jika orang berharap~juga begitu di POSIXAlasan utama saya jauh lebih menyukai CLI daripada GUI, atau terkadang TUI, adalah karena CLI terasa jauh lebih konsisten
Ada konvensi, dan mengikuti semua konvensi di CLI jauh lebih mudah daripada merancang GUI yang bagus. Karena itu, hasilnya cenderung punya kualitas lebih tinggi
Saya sering memikirkan cara membawa sifat ini ke GUI, tetapi sejauh ini jawaban terbaiknya hanya sekitar “banyak usaha” atau “menurunkan ekspektasi”
OS lain tidak berhasil memantapkan tombol meta untuk shortcut GUI, sehingga konflik seperti
ctrl-cjauh lebih sering terjadiDefault framework aplikasi yang menjadi dasar aplikasi native macOS menyediakan banyak operasi keyboard umum. Jika memakai kelas menu bar default dan perintah default, Command O, N, Q, X, C, V, dan sebagainya hampir datang gratis, dan jika memakai field teks standar, navigasi dengan Command/Option/Fn + tombol arah juga muncul otomatis
Windows juga cukup bagus dalam hal ini, tetapi fakta bahwa tombol modifier default-nya adalah Ctrl bisa mengganggu penggunaan aplikasi berbasis terminal, dan berbagai framework UI di dalam OS tampaknya memiliki default yang berbeda-beda
Di dunia Linux, sepertinya ini baru mungkin jika seseorang merancang framework aplikasi yang lengkap, distribusi menstandarkannya, dan aplikasi-aplikasi dipindahkan ke sana. Window manager tidak ingin mengatur perilaku di dalam jendela, GUI toolkit tidak ingin mendefinisikan default seluruh OS, dan desktop environment maupun distribusi juga tidak ingin bertanggung jawab memaksa atau memigrasikan framework UI
Program sebaiknya tidak menambahkan file ke direktori home dan harus menghormati konfigurasi seperti XDG_CONFIG_HOME
Ini bukan tulisan yang berusaha meyakinkan bagaimana aplikasi seharusnya berperilaku, melainkan daftar perilaku yang umum terlihat di aplikasi
Ada pengecualian untuk aturan “Ctrl-W harus menghapus kata terakhir”, yaitu mysql(1)
Karena mysql ditautkan ke editline alih-alih readline, secara default Ctrl-W menghapus semuanya sampai awal baris, bukan kata terakhir
Saat harus memakainya selama beberapa waktu, query yang sudah saya tulis dengan susah payah lenyap seluruhnya, dan rasanya benar-benar bikin gila
Saat kuliah, saya pernah sial mencoba memakai sqlplus untuk terhubung ke database Oracle; bukan hanya shortcut terminal seperti Ctrl-W sama sekali tidak berfungsi, saya juga tidak bisa memindahkan kursor ke belakang di dalam baris, dan tidak ada penelusuran riwayat untuk kembali ke perintah sebelumnya
Begitu ada satu typo saja, saya harus mengetik ulang semuanya dari awal; mengetik satu
/memang bisa menjalankan perintah terakhir apa adanya, tetapi itu tidak membantu memperbaiki typoCtrl-L untuk membersihkan layar juga tidak berfungsi; sebagai gantinya harus menjalankan
clear scrsecara manual. Mungkin kalau perintahnya cumaclearterasa terlalu jelasSaya ingin menambahkan bahwa proses yang berjalan lama seharusnya membaca ulang konfigurasi saat menerima SIGHUP
Bedanya besar, dan sayangnya item ini tidak cukup umum untuk masuk ke daftar aslinya
Proses berjalan lama yang merespons SIGHUP biasanya berjalan terpisah tanpa TTY pengendali, jadi agak sulit menyebutnya “program terminal”
Aplikasi harus berhati-hati agar tidak secara tidak sengaja menyimpan cache bukan hanya status konfigurasi, tetapi juga status yang diturunkan dari konfigurasi; kalau tidak, keduanya akan tidak sinkron
Pada aplikasi sederhana mungkin mudah, tetapi sebagian besar aplikasi yang membutuhkan file konfigurasi tidak sesederhana itu