- Terminalde hissedilen davranış; işletim sistemi, kabuk, terminal emülatörü kadar tek tek programların geleneklerinin birleşimiyle oluşur ve bu gelenekler sanılandan daha tutarlıdır
- POSIX çoğunlukla terminal emülatörü, işletim sistemi ve kabuğun etkileşimini ve bazı temel yardımcı araçları ele alır; ancak
htop gibi programların ayrıntılı davranışlarını belirlemez
Ctrl-C, q, Ctrl-D, 16 ANSI rengi, readline tuş atamaları, pipe çıktısında rengin devre dışı bırakılması, - işaretinin stdin/stdout anlamı gibi kalıplar tekrar tekrar görülür
- Doğa yasası gibi hissettiren davranışlar bile gerçekte program veya girdi kütüphanesi tarafından uygulanmalıdır;
ipython'ın Ctrl-D ile çıkışı ve prompt-toolkit'in Ctrl-C ile aramayı iptal etmesi bunun örnekleridir
- Yeni bir terminal programı geliştirirken veya bir aracın davranışını anlamaya çalışırken, “her şey mümkündür” yaklaşımından ziyade varsayılan beklentilere ve istisnalara önce bakmak daha pratiktir
Terminal davranışını oluşturan dört aktör
- Terminalde olan bitenler, genel olarak dört aktörün birlikte ortaya çıkardığı sonuç olarak görülebilir
- işletim sistemi
- kabuk
- terminal emülatörü
top, vim, cat gibi o anda çalışan program
- bash, GNOME Terminal ve Linux gibi kombinasyonlarda ilk üç unsur nispeten iyi bilinir ve bazı davranışlar POSIX ile standartlaştırılmıştır
- Tek tek programlar sanki her şeyi yapabilirmiş gibi görünse de, gerçek kullanım deneyiminde oldukça tutarlı biçimde davranırlar
Standart az, gelenek çok
- Terminal programlarının davranışını kapsamlı biçimde belirleyen gerçek standartlar neredeyse yoktur
- En yakın iki referans şunlardır
- POSIX: çoğunlukla terminal emülatörü, işletim sistemi ve kabuğun etkileşimini ele alır; ayrıca
cp gibi bazı temel yardımcı araçların davranışlarını da belirler
- command line interface guidelines: komut satırı arayüzü geleneklerini ele alan bir rehber
- Bu kurallar, program yazarlarının mutlaka uyması gereken reçetelerden çok, 20 yıllık terminal kullanımında gözlemlenmiş teknik geleneklere yakındır
- İstisna çoktur ve bu istisnaların çoğunun da geçerli nedenleri vardır
Bazı kurallar program tarafından doğrudan uygulanmalıdır
- Yapılandırma dosyalarının konumu,
--help çıktısı, normal çıktının stdout'a ve hataların stderr'e yazılması gibi konularda sorumluluğun programda olduğu nispeten açıktır
- Buna karşılık bazı davranışlar doğal görünse de gerçekte program veya girdi kütüphanesi tarafından doğrudan ele alınmalıdır
- REPL'den
Ctrl-D ile çıkış bunun tipik bir örneğidir
cat, ek bir uygulama olmadan cooked mode içinde işletim sisteminden EOF alır
ipython, Ctrl-D işlemesini prompt-toolkit koduyla uygular
- Bu uygulama sorumluluğunu anlamak, programlar arasında ayrıntılı davranışların neden biraz farklı olduğunu daha az şaşırtıcı kılar
Kural 1: Etkileşimsiz programlar Ctrl-C ile sonlanır
- Etkileşimsiz programlar genellikle
Ctrl-C basıldığında sonlanır
- Çünkü program
SIGINT sinyal işleyicisi tanımlamadıysa, varsayılan olarak Ctrl-C ile kapanır
- Bu kural
python3, bc, less gibi etkileşimli programlara aynı şekilde uygulanmaz
- Etkileşimli programlarda
Ctrl-C, programı kapatmak yerine o anda çalışan işi durdurabilir
less içindeki arama veya python3 içinde çalışan Python kodu buna örnektir
ipython'ın kullandığı girdi işleme kütüphanesi prompt-toolkit içinde, Ctrl-C ile aramayı iptal eden bir kod bulunur
Kural 2: TUI'ler genellikle q ile kapanır
less, htop gibi TUI programları genellikle q tuşuna basıldığında kapanır
- Bu kural,
q ile çıkmanın doğal olmadığı programlar için geçerli değildir
Kural 3: REPL'ler boş satırda Ctrl-D ile kapanır
python3, ed gibi REPL'ler genellikle boş satırda Ctrl-D basıldığında kapanır
- Cooked mode içinde
cat gibi bir program çalıştırıldığında, işletim sistemi boş satırdaki Ctrl-D için EOF döndürür
sqlite3, python3, fish, bash gibi araçlar gerçekte cooked mode kullanmasa da, varsayılan davranışı taklit etmek için bu kısayolu uygular
- Uygulama örnekleri iki yerde görülebilir
- Erlang REPL,
Ctrl-D ile kapanmayan bir istisnadır
Kural 4: 16 temel rengin dışına çıkmamak
- Terminal programları genel olarak temel 16 ANSI rengi dışındaki renkleri pek kullanmaz
- Hex renkleri doğrudan belirtmek, kullanıcının arka plan rengiyle çakışma ihtimalini artırır
- Örneğin
#EEEEEE metin, beyaz arka planda neredeyse görünmez olabilirken koyu arka planda sorun çıkarmayabilir
- Temel 16 renk kullanıldığında, kullanıcının bu renkleri terminal emülatöründe arka planıyla uyumlu olacak şekilde ayarlamış olma ihtimali yüksektir
- Bu yaklaşım ayrıca terminal emülatörünün desteklediği renklere dair varsayımları da azaltır
- Metin editörleri bir istisnadır
- Helix varsayılan olarak ANSI temel renkleri yerine mor bir arka plan kullanır
- Helix “çekirdek” bir program olarak görülmez ve renk şemasını sevmeyen kullanıcıların temayı değiştirebileceği varsayılır
Kural 5: readline tuş atamalarını bir ölçüde desteklemek
- Anlamlı olduğu durumlarda neredeyse tüm programlar readline tuş atamalarını bir ölçüde destekler
- Birçok program
readline'ı doğrudan kullanmasa da emacs/readline tarzı tuş atamalarını taklit eder
- Tüm programlar bunu tam olarak aynı şekilde taklit etmez
- atuin, görünüşe göre
Ctrl-A tuşunu prefix olarak kullanıyor; bu yüzden Ctrl-A satırın başına gitmiyor
- Bu programlar kendi kes-yapıştır tamponlarını uygular; böylece
Ctrl-U ile satırı silip ardından Ctrl-Y ile yapıştırmak mümkündür
- İstisnalar da vardır
git, cat, nc gibi programlarda backspace, Ctrl-W, Ctrl-U dışında satır düzenleme desteği yoktur
- metin editörlerinin her birinin kendine özgü düzenleme yöntemi vardır
- İlgili konu entering text in the terminal is complicated yazısında daha ayrıntılı ele alınır
Kural 5.1: Ctrl-W son kelimeyi siler
- Metin editörleri dışında,
Ctrl-W'nin son kelimeyi silmediği bir program görülmediği söyleniyor
- Cooked mode içinde işletim sistemi varsayılan olarak
Ctrl-W basıldığında son kelimeyi, Ctrl-U basıldığında ise tüm satırı siler
- Birçok program bu varsayılan davranışı taklit eder
- Metin editörleri dışında akla gelen bir istisna yoktur
Kural 6: Pipe'a yazarken renkleri kapatmak
- Programların çoğu, çıktı hedefi pipe olduğunda renkleri devre dışı bırakır
- Örnekler
rg blah, terminal çıktısında blah ifadesini vurgular; ancak pipe veya dosyaya yazarken bu vurguyu kapatır
ls --color=auto, terminale yazarken renk kullanır, pipe'a yazarken kullanmaz
- Çıktı biçimi de terminale yazılıp yazılmamasına göre değişebilir
ls, terminal çıktısında dosyaları sütunlar halinde düzenler
- ripgrep, eşleşmeleri başlıklarla birlikte gruplar
- Renkleri zorla görmek isterseniz, program çıktısını tty gibi göstermek için
unbuffer kullanılabilir
unbuffer rg blah | less -R
- Bazı programlarda renkler
--color bayrağıyla zorlanabilir
- Yukarıdaki örnek
rg --color=always | less -R ile de yapılabilir
Kural 7: - stdin veya stdout anlamına gelir
- Genellikle dosya adı yerine
- verildiğinde, program uygun yöne göre stdin'den okur veya stdout'a yazar
- Panodaki Python kodunu
black ile biçimlendirip tekrar panoya kopyalamak için şöyle çalıştırılabilir
pbpaste | black - | pbcopy
pbpaste bir Mac programıdır; Linux'ta benzer iş için xclip kullanılabilir
- Çoğu program anlamlı olduğu durumlarda bu davranışı uygular gibi görünse de, çok sayıda istisna olabilir
Bu kuralları öğrenmek neden uzun sürüyor
- Bu kurallar genellikle tek seferde açıkça öğrenilmek yerine birkaç aşamada edinilir
- Önce “
Ctrl-C programı kapatır” gibi bir kuralın var olduğu öğrenilir
- Sonra
find kapanırken less'in kapanmadığı gibi istisnalar fark edilir
- Etkileşimsiz programlarda bunun sonlandırma, etkileşimli programlarda ise mevcut işi durdurma anlamına gelebileceği kalıbı bilinçsizce kavranır
- Ancak daha sonra bunlar açık kurallar olarak formüle edilebilir
- Terminale dair pek çok anlayış hâlâ bilinçsiz örüntü tanıma düzeyinde kalır
- Kuralları yazıya dökmek, başkalarının terminal davranışını biraz daha hızlı öğrenmesine yardımcı olabilir
1 yorum
Hacker News yorumları
Ek olarak, terminal programları kullanıcının varsayılan ön plan/arka plan renklerine saygı göstermeli ve bunları sebepsiz yere değiştirmemeli
Renk kullanılsa bile, varsayılan arka plan/ön plan ve terminal renk paleti ne olursa olsun metin okunabilir kalmalı; ayrıca anlam yalnızca renkle verilirse kopyala/yapıştır sırasında veya renk desteklemeyen terminallerde kaybolur
Emoji ve gereksiz ASCII dışı karakterler de dikkatli kullanılmalı; kayarak akan standart çıktı biçiminde, geçici olarak gösterilen uyarılar ya da dosya adları gibi önemli bilgileri silmemek daha iyidir
Gösterişli renkler ve bol animasyon kullanmak istiyorsanız, en azından kolayca kapatılabilen bir ayar seçeneği sunmalısınız
Kök nedenin düzeltilip düzeltilmediğini bilmiyorum ama çeşitli açık kaynak projelerde, asıl sanatsal niyetten biraz ödün veren geçici çözüm PR'ları hazırlamama neden olmuştu: https://github.com/docker-archive/toolbox/issues/695
Yine de kullanıcı tanımlı renkler sunabilirsiniz
Daha çok, neredeyse tüm terminal programlarının zaten uyduğunun varsayılabileceği şeylerin bir özeti gibidir
Bugünlerde bazı yazarlar, kullanıcının patch'lenmiş yazı tipi kullandığını varsayarak araçlar geliştiriyor ve bu da kullanılabilirliği ciddi biçimde zedeliyor
Güzel bir yazı
Bu tür teamülleri öğrenmenin zor olduğundan söz edildiği için, CLI düşünürken başvurmayı sevdiğim kaynak olan Command Line Interface Guidelines'ı da öneririm: https://clig.dev
Ctrl-C ile çıkmak, standart girdide
-kabul etmek, pipe kullanılırken renkleri kapatmak gibi metindeki kuralları ve daha fazlasını içeriyorPOSIX, GNU, Unix kaynakları, Heroku CLI rehberi ve 12-factor CLI uygulama rehberi yer alıyor
“Normal çıktı stdout'a, hatalar stderr'e yazılmalı” noktası gerçekten çok önemli
Standart çıktı, yalnızca programdan üretilmesi istenen veriler için ayrılmış yer olmalı. Kullanıcı JSON verisi istediyse, standart çıktıda yalnızca ve tam olarak o JSON nesnesi bulunmalı; başka hiçbir şey asla karışmamalı
Standart hata adı aslında biraz yanıltıcı; bu akış daha çok, terminalde kullanıcının okuması gereken tüm mesajların gönderildiği bir “standart kullanıcı akışı”na benziyor. Buna yalnızca hata mesajları değil, durum mesajları ve ayrıntılı çıktı da dahildir
Böylece program çıktısı başka programlara sorunsuzca pipe edilebilir; veri olmayan bilgiler ise yine terminale gidebilir veya başka bir yere yönlendirilebilir
Programların, belirli amaçlı terminal bağlantısı file descriptor'larını kolayca yeniden oluşturabilmesi ve çıkış kodlarında olduğu gibi bu numaraları kılavuzda belgeleyebilmesi iyi olurdu. Uyumluluk için varsayılan olarak stdout veya stderr kullanılabilir; bunu biraz denemeyi düşünüyorum
6 farklı akış var ve her biri ayrı ayrı yakalanabiliyor ya da farklı şekilde ayarlanabiliyor: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_output_streams?view=powershell-7.4
grepgibi işlemleri çalıştırmayacağı için kafa karıştırıcı olabilirAyrıca birkaç not: readline/emacs tuş kısayolları olan Ctrl-E ve Ctrl-W'yi ilk kez duyuyorsanız, çoğu macOS giriş kaynağının bu tuş kısayollarını kullandığını bilmek faydalı olabilir
macOS kullanıyorsanız, şu anda tarayıcı adres çubuğunda Ctrl-E, Ctrl-W ve Ctrl-U'yu deneyebilirsiniz
Hiç satır düzenleme desteklemeyen bir komut satırı programı kullanıyorsanız,
rlwrapkurup REPL'i onun altında çalıştırabilirsiniz. Örneğin Standard ML of New Jersey'de REPL var ama satır düzenleme yoktur; bu yüzdenrlwrap smlnjile telafi edilebilir“16 renkten fazlasını kullanmayın” ifadesinin de ötesine geçip “8 renkten fazlasını kullanmayın ya da en azından renkleri yapılandırılabilir hale getirin” demek isterim. Solarized ve varsayılan Base 16 gibi popüler paletler, “parlak” renkleri çeşitli gri tonları için de kullanabildiğinden, yazarın parlak yeşil sandığı şey gerçekte normal metinle aynı gri olabilir
Kullandığım terminal emülatörü Alacritty'de de böyle; sekmeli çoğu dosya gezgini de aynı şekilde davranıyor. Yanlış hatırlamıyorsam Windows Explorer da artık böyle, ama Windows kullanmayalı epey oldu
REPL'de Ctrl-D ile çıkma geleneği, GHCi'de sürekli ayağıma dolaşıyor
Genelde Ctrl-D'ye basıyorum, hiçbir şey olmayınca afallıyorum, sonra GHCi'de bunun çalışmadığını hatırlayıp
:qçalıştırıyorumSonra Ctrl-D, girdinin en başına görünmez bir karakter ekliyor ve
“lexical error at character '\EOT'”hatası çıkıyor; GHCi'den çıkmak için görünmez önek olmadan:qyu yeniden yazmak gerekiyorBaşka yöntem ne, onu da pek bilmiyorum; bu davranışı değiştiren bir ayar var mı?
Eksik kalan bir şey de
~karakterinin home dizini olarak ele alınmasıBu bir POSIX API'si değil, kabuk özelliği gibi görünüyor. Go'da
os.ReadFile("~/.bashrc")çalışmaz ama kabuktaecho ~/~/~,/home/jrockway/~/~gibi genişleryourprogram ~/path/to/fileher zaman çalışır, ama dosya adı soran bir REPL'de çalışmayabilir. Gerçekte birçok yazılım bunu destekliyor; bu yüzden bence “çoğu TUI programının yaptığı şeyler” arasında sayılabilirSözcük genişletmede tilde genişletme ilk adımdır; ardından alan bölme, yol adı genişletme ve tırnak kaldırma gelir
İlgili kabuk belirtimi https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html#tag_19_06 adresindedir; tüm belirtim ise https://pubs.opengroup.org/onlinepubs/9799919799/ adresinde görülebilir
Bir araç tilde genişletme eklerse mevcut kullanıcının home dizinini bilmek zorunda kalır; bu da uygulamayı karmaşıklaştırır ve
~çalışırken~nameçalışmayan eksik uygulamalara yol açabilirPOSIX kabuğunda
~name, ilgili kullanıcının home dizinine genişler; yani sistem kullanıcıları da dahil rastgele kullanıcıların home dizinlerini sorgulamak gerekir. NSS yapılandırmasına bağlı olarak bu,/etc/passwdokumaktan çok daha karmaşık olabilirEtkileşimli bir TUI için tilde genişletmeyi uygulamak faydalı olabilir, ama o durumda kabuk kadar eksiksiz olmalıdır. CLI programlarının böyle sihirli genişletmeler yapmaması daha iyidir
Adı
"~"olan bir dosya varsa ne olacağı,"~username"için ne yapılacağı, nasıl kaçışlama/alıntılama yapılacağı,$HOMEyoksa ya da gerçek home ile farklıysa ne olacağı ve Windows'ta nasıl davranacağı gibi sorunlar çıkarDaha az bilinen bir gerçek de şu: ssh'de satır sonundan sonra
"~."yazarsan istemci tarafı bağlantıyı zorla kapatır ve sunucunun yapabileceği hiçbir şey kalmaz; bu yüzden bunu iş akışına dahil etmemek iyi olur./myprogram --config=~/.config/myprogrambiçimiElbette birçok bayrak ayrıştırıcı, kabuğun genişlettiği
./myprogram --config ~/.config/myprogrambiçimini kullanmana izin veriyor; yani bunu ya biliyor ya da tesadüfen destekliyorlarAma kas hafızası yüzünden ille de
=yazıyorum. Sanırım önceki iş yerimdeki bayrak ayrıştırma kütüphanesinden kalma bir alışkanlık; aynı nedenle--hyphens-like-normal-peopleyerine hep--underscores_like_thisde kullanıyorumÖzellikle
..OS API düzeyinde işlendiği için, POSIX'te~için de bunun böyle olmasını beklemek kolayCLI'yi GUI'den, hatta bazen TUI'den bile çok daha fazla sevmemin ana nedeni, çok daha tutarlı hissettirmesi
Gelenekler var ve CLI'de tüm bu geleneklere uymak, iyi bir GUI tasarlamaktan çok daha kolay. Bu yüzden sonuçta kalite daha yüksek olma eğiliminde
Bu özelliği GUI'ye taşımanın yollarını çok düşündüm ama şimdiye kadar en iyi cevaplar “çok emek” ya da “beklentileri düşürmek” oldu
Diğer işletim sistemleri, GUI kısayolları için bir meta tuşu yerleştirmeyi başaramadı; bu yüzden
ctrl-cgibi çakışmalar çok daha fazla oluyormacOS yerel uygulamalarının temelini oluşturan uygulama çatısı varsayılanları, birçok ortak klavye etkileşimini hazır sunuyor. Varsayılan menü çubuğu sınıfını ve varsayılan komutları kullanırsan Command O, N, Q, X, C, V vb. neredeyse bedavaya geliyor; standart metin alanlarını kullanırsan Command/Option/Fn + ok tuşlarıyla gezinme de otomatik olarak ekleniyor
Windows da bu açıdan oldukça iyi, ancak varsayılan yardımcı tuşun Ctrl olması terminal tabanlı uygulamaların kullanımını zorlaştırabiliyor ve işletim sistemi içindeki farklı UI çatıları birbirinden farklı varsayılanlara sahipmiş gibi görünüyor
Linux dünyasında bunun olması için birilerinin eksiksiz bir uygulama çatısı tasarlaması, dağıtımların bunu standartlaştırması ve uygulamaların taşınması gerekiyor gibi görünüyor. Pencere yöneticileri pencerenin içindeki davranışı dikte etmek istemiyor, GUI araç takımları işletim sistemi genelindeki varsayılanları tanımlamak istemiyor ve masaüstü ortamlarıyla dağıtımlar da bir UI çatısını dayatmak ya da taşımak işini üstlenmek istemiyor
Programlar home dizinine dosya eklememeli; XDG_CONFIG_HOME gibi ayarlara uymalı
Uygulamaların nasıl davranması gerektiğini savunmaya çalışmıyor; uygulamalarda sıkça görülen davranışları sıralıyor
“Ctrl-W son kelimeyi silmelidir” kuralının bir istisnası olarak mysql(1) var
mysql, readline yerine editline ile bağlantılı olduğu için, varsayılan olarak Ctrl-W son kelimeyi değil satırın başına kadar her şeyi siliyor
Bunu bir süre kullanmam gerektiğinde, özenle yazdığım sorgunun tamamen yok olması gerçekten çıldırtıcıydı
Üniversitedeyken Oracle veritabanına bağlanmak için sqlplus kullanmayı denemek gibi talihsiz bir deneyimim olmuştu; Ctrl-W gibi terminal kısayolları hiç çalışmadığı gibi, imleci satır içinde ileri taşımak da mümkün değildi ve önceki komutlara gitmek için bir geçmiş gezintisi de yoktu
Tek bir yazım hatasında bile her şeyi en baştan yeniden yazmak gerekiyordu;
/girerek son komutu aynen çalıştırmak mümkün olsa da bu, yazım hatasını düzeltmeye hiç yardımcı olmuyorduCtrl-L ile ekranı temizlemek de çalışmıyordu; onun yerine doğrudan
clear scrçalıştırmak gerekiyordu. Komutun sadececlearolması fazla mı bariz gelmiş acabaUzun süre çalışan süreçlerin SIGHUP aldıklarında yapılandırmayı yeniden okuması gerektiğini eklemek isterim
Arada büyük bir fark var ve ne yazık ki bu madde orijinal listeye girecek kadar yaygın değil
SIGHUP'a tepki veren uzun süre çalışan süreçler genelde bir kontrol TTY'si olmadan ayrık şekilde çalıştığından, bunlara “terminal programı” demek biraz zor
Uygulamanın yalnızca yapılandırma durumunu değil, yapılandırmadan türetilen durumu da yanlışlıkla önbelleğe almamasına dikkat etmek gerekir; aksi halde ikisi birbirinden sapar
Basit uygulamalarda kolay olabilir ama yapılandırma dosyasına ihtiyaç duyan çoğu uygulama o kadar basit değil