- टर्मिनल का महसूस होने वाला व्यवहार सिर्फ़ ऑपरेटिंग सिस्टम, shell और terminal emulator से नहीं, बल्कि अलग-अलग programs की conventions से भी मिलकर बनता है, और ये conventions उम्मीद से ज़्यादा consistent होती हैं
- POSIX मुख्य रूप से terminal emulator, ऑपरेटिंग सिस्टम और shell के interaction और कुछ core utilities को कवर करता है, लेकिन
htop जैसे programs के detailed behavior को तय नहीं करता
Ctrl-C, q, Ctrl-D, 16 ANSI colors, readline key bindings, pipe output में colors disable करना, - का stdin/stdout अर्थ जैसे patterns बार-बार दिखते हैं
- जो behavior natural law जैसा लगता है, उसे भी असल में program या input library को implement करना पड़ता है;
ipython में Ctrl-D से exit और prompt-toolkit में Ctrl-C से search रोकना इसके उदाहरण हैं
- नया terminal program बनाते समय या tools का behavior समझते समय “कुछ भी possible है” के बजाय default expectations और exceptions को पहले देखना ज़्यादा practical है
टर्मिनल behavior बनाने वाले चार पक्ष
- टर्मिनल में जो कुछ होता है, उसे आम तौर पर चार पक्षों के साथ मिलकर बने नतीजे के रूप में देखा जा सकता है
- ऑपरेटिंग सिस्टम
- shell
- terminal emulator
top, vim, cat जैसे अभी चल रहे programs
- bash, GNOME Terminal, Linux जैसे combinations में पहले तीन elements अपेक्षाकृत अच्छी तरह जाने जाते हैं, और कुछ behavior POSIX से standardized हैं
- अलग-अलग programs देखने में ऐसा लग सकता है कि वे कुछ भी कर सकते हैं, लेकिन वास्तविक user experience में वे काफ़ी consistent तरीके से behave करते हैं
Standards कम हैं, लेकिन conventions हैं
- terminal programs के behavior को comprehensive तरीके से तय करने वाले actual standards बहुत कम हैं
- नज़दीकी references के तौर पर दो चीज़ें हैं
- POSIX: मुख्य रूप से terminal emulator, ऑपरेटिंग सिस्टम और shell के interaction को कवर करता है, और
cp जैसी कुछ core utilities के behavior भी तय करता है
- command line interface guidelines: command-line interface conventions को कवर करने वाली guide
- ये rules program authors के लिए अनिवार्य prescriptions नहीं हैं, बल्कि 20 साल तक terminal इस्तेमाल करते हुए observe की गई technical conventions के ज़्यादा करीब हैं
- Exceptions बहुत हैं, और exceptions के पीछे अक्सर valid reasons होते हैं
कुछ rules program को खुद implement करने पड़ते हैं
- config file location,
--help output, normal output को stdout में और errors को stderr में लिखना—इनकी जिम्मेदारी program की है, यह अपेक्षाकृत साफ़ है
- दूसरी तरफ़ कुछ behavior natural लगते हैं, लेकिन असल में program या input library को उन्हें directly handle करना पड़ता है
Ctrl-D से REPL exit करना इसका representative example है
cat में अलग implementation के बिना cooked mode में ऑपरेटिंग सिस्टम EOF return करता है
ipython prompt-toolkit code से Ctrl-D handling implement करता है
- इस implementation responsibility को समझने पर यह कम surprising लगता है कि हर program में detailed behavior थोड़ा अलग क्यों होता है
Rule 1: non-interactive programs Ctrl-C से exit होते हैं
- Non-interactive programs आम तौर पर
Ctrl-C दबाने पर exit हो जाते हैं
- अगर program ने
SIGINT signal handler set नहीं किया है, तो Ctrl-C पर default रूप से exit होता है
- यह rule
python3, bc, less जैसे interactive programs पर वैसे ही apply नहीं होता
- interactive programs में
Ctrl-C program exit नहीं, बल्कि current running task को interrupt कर सकता है
less में search या python3 में चल रहा Python code इसके examples हैं
ipython जिस input processing library prompt-toolkit का इस्तेमाल करता है, उसमें Ctrl-C से search रोकने का code है
Rule 2: TUI आम तौर पर q से exit होता है
less, htop जैसे TUI programs आम तौर पर q दबाने पर exit होते हैं
- यह rule उन programs पर apply नहीं होता जहाँ
q से exit करना natural नहीं है
Rule 3: REPL खाली line पर Ctrl-D से exit होता है
python3, ed जैसे REPL आम तौर पर खाली line पर Ctrl-D दबाने से exit होते हैं
- cooked mode में
cat जैसे program चलाने पर ऑपरेटिंग सिस्टम खाली line के Ctrl-D पर EOF return करता है
sqlite3, python3, fish, bash आदि असल में cooked mode इस्तेमाल नहीं करते, लेकिन default behavior की नकल करने के लिए इस shortcut को implement करते हैं
- Implementation examples दो जगह देखे जा सकते हैं
- Erlang REPL एक exception है जो
Ctrl-D से exit नहीं होता
Rule 4: 16 default colors से आगे नहीं जाते
- terminal programs आम तौर पर default 16 ANSI colors के अलावा colors बहुत कम इस्तेमाल करते हैं
- hex color को directly specify करने पर user के background color से clash होने की संभावना बड़ी होती है
- उदाहरण के लिए
#EEEEEE text सफ़ेद background पर लगभग दिखाई नहीं देगा, लेकिन dark background पर ठीक हो सकता है
- default 16 colors इस्तेमाल करने पर संभावना अधिक है कि user ने terminal emulator में colors को background color के साथ अच्छी तरह match करके set किया होगा
- यह तरीका terminal emulator द्वारा supported colors के बारे में assumptions भी कम करता है
- एक exception text editors हैं
- Helix by default ANSI default color नहीं, बल्कि purple background इस्तेमाल करता है
- Helix कोई “core” program नहीं है, और माना जाता है कि जिन्हें color scheme पसंद नहीं है वे theme बदल सकते हैं
Rule 5: readline key bindings को कुछ हद तक support करना
- जहाँ meaningful हो, लगभग हर program readline key bindings को कुछ हद तक support करता है
- कई programs
readline को directly इस्तेमाल नहीं करते, लेकिन emacs/readline style key bindings की नकल करते हैं
- सभी programs बिल्कुल same तरीके से नकल नहीं करते
- atuin में लगता है कि
Ctrl-A को prefix के रूप में इस्तेमाल किया जाता है, इसलिए Ctrl-A line की शुरुआत में move नहीं करता
- ये programs अपने cut/paste buffers implement करते हैं, ताकि
Ctrl-U से line delete करने के बाद Ctrl-Y से paste किया जा सके
- Exceptions भी हैं
git, cat, nc जैसे programs में backspace, Ctrl-W, Ctrl-U को छोड़कर line editing support नहीं होता
- text editors के अपने-अपने unique editing methods होते हैं
- Related topic entering text in the terminal is complicated में और detail से कवर है
Rule 5.1: Ctrl-W last word delete करता है
- text editors को छोड़कर, ऐसा program मैंने नहीं देखा जिसमें
Ctrl-W last word delete न करता हो
- cooked mode में ऑपरेटिंग सिस्टम default रूप से
Ctrl-W दबाने पर last word delete करता है, और Ctrl-U दबाने पर पूरी line delete करता है
- कई programs इस default behavior की नकल करते हैं
- text editors के अलावा कोई exception याद नहीं आता
Rule 6: pipe में लिखते समय colors बंद करना
- अधिकांश programs output target pipe होने पर colors disable कर देते हैं
- Examples
rg blah terminal output में blah को highlight करता है, लेकिन pipe या file में output करते समय highlight बंद कर देता है
ls --color=auto terminal में लिखते समय colors इस्तेमाल करता है, और pipe में लिखते समय colors इस्तेमाल नहीं करता
- Output terminal है या नहीं, इसके आधार पर format भी बदल सकता है
ls terminal output में files को columns में arrange करता है
- ripgrep matches को title के साथ group करता है
- अगर colors force करके देखना चाहते हैं, तो
unbuffer से program output को tty जैसा बना सकते हैं
unbuffer rg blah | less -R
- कुछ programs
--color flag से colors force कर सकते हैं
- ऊपर वाला example
rg --color=always | less -R से भी possible है
Rule 7: - stdin या stdout होता है
- आम तौर पर file name की जगह
- देने पर program appropriate direction में stdin पढ़ता है या stdout में लिखता है
- clipboard के Python code को
black से format करके फिर copy करना हो, तो इस तरह चला सकते हैं
pbpaste | black - | pbcopy
pbpaste Mac program है, और Linux में xclip से मिलती-जुलती चीज़ की जा सकती है
- अधिकांश programs meaningful होने पर यह तरीका implement करते दिखते हैं, लेकिन exceptions बहुत हो सकते हैं
Rules सीखने में लंबा समय क्यों लगता है
- ऐसे rules एक बार में explicitly सीखने के बजाय कई stages से गुजरकर सीखे जाते हैं
- पहले यह सीखते हैं कि “
Ctrl-C program को exit करता है” जैसा कोई rule मौजूद है
- फिर exceptions मिलते हैं, जैसे
find exit होता है लेकिन less exit नहीं होता
- unconsciously यह pattern समझ आता है कि non-interactive programs में exit होता है, और interactive programs में सिर्फ़ current task interrupt हो सकता है
- बाद में ही इसे explicit rule के रूप में organize किया जा सकता है
- terminal की बहुत-सी understanding अब भी unconscious pattern recognition के stage में रहती है
- rules को लिखकर organize करने से दूसरे लोग terminal behavior थोड़ा जल्दी सीख सकते हैं
1 टिप्पणियां
Hacker News टिप्पणियाँ
इसके अलावा, terminal programs को यूज़र के default foreground/background रंगों का सम्मान करना चाहिए और बिना वजह उन्हें बदलना नहीं चाहिए
रंग इस्तेमाल भी करें तो default background/foreground और terminal color palette कुछ भी हो, वह पढ़ने योग्य होना चाहिए; और अगर अर्थ सिर्फ रंग से बताया गया, तो copy/paste या रंग support न करने वाले terminal में वह गायब हो जाता है
emoji या गैर-ज़रूरी non-ASCII characters भी सोच-समझकर इस्तेमाल करने चाहिए, और scrolling standard output वाले रूप में बेहतर है कि अस्थायी रूप से दिखाए गए warning या filename जैसी महत्वपूर्ण जानकारी मिटाई न जाए
अगर आप बहुत सारे चमकीले रंग और animations इस्तेमाल करना चाहते हैं, तो कम-से-कम उन्हें आसानी से बंद करने का configuration option देना चाहिए
पता नहीं मूल कारण ठीक हुआ या नहीं, लेकिन कई open source projects में मूल artistic intent से थोड़ा समझौता करने वाले workaround PR बनाने पड़े: https://github.com/docker-archive/toolbox/issues/695
हालांकि user-defined colors उपलब्ध कराए जा सकते हैं
कुल मिलाकर यह उन बातों की सूची के करीब है जिनके बारे में माना जा सकता है कि लगभग सभी terminal programs पहले से पालन करते हैं
आजकल कुछ authors यह मानकर tools बनाते हैं कि user patched font इस्तेमाल करता है, जिससे usability काफ़ी खराब हो जाती है
अच्छा लेख है
इसमें कहा गया है कि ऐसी conventions सीखना मुश्किल है, इसलिए CLI के बारे में सोचते समय मेरा पसंदीदा reference Command Line Interface Guidelines भी recommend करता हूँ: https://clig.dev
इसमें Ctrl-C से exit करना, standard input में
-लेना, pipes में रंग बंद करना जैसे मूल लेख के rules और उससे भी ज़्यादा चीज़ें शामिल हैंइसमें POSIX, GNU, Unix resources, Heroku CLI guide, और 12-factor CLI app guide शामिल हैं
“सामान्य output stdout पर और errors stderr पर output करने चाहिए” वाली बात सचमुच महत्वपूर्ण है
standard output सिर्फ उस data के लिए होना चाहिए जिसे program से generate करने के लिए कहा गया है। अगर user ने JSON data माँगा है, तो standard output में सिर्फ वही JSON object ठीक-ठीक होना चाहिए और कुछ भी नहीं
standard error नाम असल में थोड़ा गलत रखा गया है; यह terminal में user द्वारा पढ़े जाने वाले सभी messages भेजने वाली “standard user stream” के ज्यादा करीब है। इसमें सिर्फ error messages ही नहीं, status messages और verbose output भी आते हैं
तभी program output को दूसरे program में smoothly pipe किया जा सकता है, और non-data information फिर भी terminal पर जा सकती है या कहीं और redirect हो सकती है
अच्छा होगा अगर program किसी specific purpose के terminal connection file descriptor को आसानी से नया बना सके, और exit codes की तरह manual में उनके numbers document कर सके। compatibility के लिए default stdout या stderr पर भेजा जा सकता है, और मैं इसे थोड़ा experiment करके देखने की सोच रहा हूँ
इसमें 6 अलग-अलग streams हैं और हर एक को अलग से intercept या अलग तरह से configure किया जा सकता है: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_output_streams?view=powershell-7.4
grepजैसी processing काम नहीं करेगी और confusion हो सकता हैकुछ और बातें: अगर readline/emacs key bindings Ctrl-E, Ctrl-W पहली बार सुन रहे हैं, तो यह जानना अच्छा होगा कि ज्यादातर macOS input sources ये key bindings इस्तेमाल करते हैं
macOS पर आप अभी browser address bar में Ctrl-E, Ctrl-W, Ctrl-U आज़मा सकते हैं
अगर आप ऐसा command-line program इस्तेमाल करते हैं जो line editing बिल्कुल support नहीं करता, तो
rlwrapinstall करके REPL को उसके नीचे चला सकते हैं। उदाहरण के लिए Standard ML of New Jersey में REPL तो है लेकिन line editing feature नहीं है, इसलिएrlwrap smlnjसे इसकी कमी पूरी की जा सकती है“16 colors से ज़्यादा इस्तेमाल न करें” वाली बात पर मैं आगे बढ़कर कहना चाहूँगा, “8 colors से ज़्यादा इस्तेमाल न करें, या कम-से-कम colors configurable रखें।” Solarized और default Base 16 जैसी popular color palettes में “bright” colors को कई स्तरों के grey के लिए इस्तेमाल किया जाता है, इसलिए author ने जिस bright green की कल्पना की हो, वह असल में normal text जैसा ही grey हो सकता है
मेरा terminal emulator Alacritty भी ऐसा ही करता है, और tabs वाले ज्यादातर file explorers भी इसी तरह behave करते हैं। याद से कहूँ तो Windows Explorer भी अब शायद ऐसा ही है, लेकिन Windows इस्तेमाल किए काफी समय हो गया है
REPL में Ctrl-D से बाहर निकलने की परंपरा GHCi में मुझे हमेशा फंसा देती है
आम तौर पर मैं Ctrl-D दबाता हूं, कुछ नहीं होता तो घबरा जाता हूं, फिर याद आता है कि GHCi में यह नहीं चलता और
:qचलाता हूंतब Ctrl-D इनपुट की शुरुआत में एक अदृश्य कैरेक्टर डाल देता है, जिससे “lexical error at character '\EOT'” त्रुटि आती है, और GHCi बंद करने के लिए मुझे उस अदृश्य प्रीफिक्स के बिना फिर से
:qटाइप करना पड़ता हैदूसरा तरीका क्या है, यह भी ठीक से नहीं जानता; क्या इस व्यवहार को बदलने की कोई सेटिंग है?
एक छूटी हुई चीज़
~को home directory मानने वाला व्यवहार हैयह POSIX API नहीं, बल्कि shell feature लगता है। Go में
os.ReadFile("~/.bashrc")काम नहीं करता, लेकिन shell मेंecho ~/~/~/home/jrockway/~/~की तरह expand हो जाता हैyourprogram ~/path/to/fileहमेशा चलेगा, लेकिन किसी REPL में जब file name पूछा जाए तो शायद न चले। असल में बहुत-से software इसे support करते हैं, इसलिए मुझे लगता है कि यह “ज्यादातर TUI programs जो करते हैं” में शामिल होने लायक हैword expansion में tilde expansion पहला चरण है, जिसके बाद field splitting, pathname expansion और quote removal आते हैं
संबंधित shell spec https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html#tag_19_06 पर है, और पूरा spec https://pubs.opengroup.org/onlinepubs/9799919799/ पर देखा जा सकता है
अगर कोई tool tilde expansion जोड़ता है, तो उसे current user की home directory पता करनी पड़ेगी, जिससे implementation complex हो जाती है, और
~तो चले लेकिन~nameन चले जैसी अधूरी implementation बन सकती हैPOSIX shell में
~nameउस user की home directory में expand होता है, इसलिए system users समेत किसी भी user की home directory query करनी पड़ेगी। NSS settings के हिसाब से यह/etc/passwdपढ़ने से कहीं ज्यादा complex हो सकता हैinteractive TUI हो तो tilde expansion implement करना उपयोगी हो सकता है, लेकिन उस स्थिति में यह shell जितना complete होना चाहिए। CLI programs को ऐसे magic expansion न करना ही बेहतर है
अगर
"~"नाम की file हो तो क्या करेंगे,"~username"का क्या होगा, escape/quote कैसे करेंगे,$HOMEन हो या actual home से अलग हो तो क्या करेंगे, Windows में क्या करेंगे—ये समस्याएं उठेंगीएक कम-जानी बात: ssh में line break के बाद
"~."टाइप करने पर client side से connection जबरन बंद हो जाता है और server कुछ नहीं कर सकता, इसलिए इसे workflow में शामिल न करना बेहतर है./myprogram --config=~/.config/myprogramजैसे रूप में परेशान करती हैबेशक कई flag parsers shell द्वारा expand किए जाने वाले रूप
./myprogram --config ~/.config/myprogramको इस्तेमाल करने देते हैं, इसलिए वे इसे जानते हैं या संयोग से support कर देते हैंलेकिन muscle memory की वजह से मैं अनिवार्य रूप से
=टाइप कर देता हूं। लगता है यह मेरे पुराने workplace की flag parsing library से बनी आदत है, और इसी वजह से मैं--hyphens-like-normal-peopleके बजाय हमेशा--underscores_like_thisभी लिखता हूंखासकर
..OS API स्तर पर handle होता है, इसलिए POSIX में~के भी वैसा ही होने की उम्मीद करना आसान हैCLI को GUI या कभी-कभी TUI से कहीं ज्यादा पसंद करने की मेरी मुख्य वजह यह है कि यह बहुत ज्यादा consistent महसूस होता है
conventions हैं, और CLI में सभी conventions follow करना एक अच्छे GUI को design करने से कहीं आसान है। इसलिए नतीजतन quality अक्सर बेहतर हो जाती है
मैं बहुत सोचता हूं कि इस property को GUI में कैसे लाया जाए, लेकिन अब तक सबसे अच्छा जवाब “बहुत मेहनत” या “expectations कम करना” ही लगता है
बाकी OS, GUI shortcuts के लिए meta key को स्थापित नहीं कर पाए, इसलिए
ctrl-cजैसे conflicts बहुत ज्यादा होते हैंmacOS native apps की नींव बनने वाले application framework defaults आम keyboard operations बहुत देते हैं। default menu bar classes और default commands इस्तेमाल करें तो Command O, N, Q, X, C, V आदि लगभग मुफ्त मिल जाते हैं, और standard text fields इस्तेमाल करें तो Command/Option/Fn + arrow key navigation भी अपने-आप आ जाता है
Windows भी इस मामले में काफी ठीक है, लेकिन default modifier key Ctrl होना terminal-based apps के इस्तेमाल में बाधा डाल सकता है, और OS के अंदर मौजूद कई UI frameworks के defaults अलग-अलग लगते हैं
Linux दुनिया में शायद यह तभी संभव होगा जब कोई पूरा application framework design करे, distributions उसे standardize करें और apps को port करें। window manager खिड़की के अंदर के behavior को निर्देशित नहीं करना चाहता, GUI toolkit पूरे OS के defaults define नहीं करना चाहता, और desktop environments व distributions भी UI framework को enforce करने या port करने का काम अपने ऊपर नहीं लेना चाहते
Programs को home directory में files add नहीं करनी चाहिए और XDG_CONFIG_HOME जैसी settings का सम्मान करना चाहिए
यह applications को कैसे behave करना चाहिए यह मनवाने की कोशिश नहीं है, बल्कि applications में आम तौर पर देखे गए behavior की सूची है
“Ctrl-W को आखिरी शब्द हटाना चाहिए” वाले नियम का एक अपवाद mysql(1) है
mysql, readline के बजाय editline से लिंक होता है, इसलिए default रूप से Ctrl-W आखिरी शब्द नहीं, बल्कि लाइन की शुरुआत तक सब कुछ मिटा देता है
जब मुझे कुछ समय तक इसे इस्तेमाल करना पड़ा, तो बहुत मेहनत से लिखी query पूरी की पूरी गायब हो जाती थी और सच में पागल कर देने वाला अनुभव था
कॉलेज के दिनों में Oracle database से connect करने के लिए sqlplus आज़माने का दुर्भाग्य हुआ था; Ctrl-W जैसे terminal shortcuts तो बिल्कुल काम नहीं करते थे, लाइन के अंदर cursor को आगे भी नहीं ले जा सकते थे, और पिछले commands पर जाने के लिए history navigation भी नहीं था
एक typo होते ही पूरा फिर से शुरुआत से type करना पड़ता था, और
/टाइप करने पर आखिरी command जस-का-तस चलाया जा सकता था, लेकिन typo ठीक करने में उससे कोई मदद नहीं मिलती थीCtrl-L से screen clear भी नहीं होता था; इसकी जगह
clear scrखुद चलाना पड़ता था। शायद command को बसclearरखना बहुत ही obvious लग रहा होगामैं यह भी जोड़ना चाहूँगा कि long-running processes को SIGHUP मिलने पर configuration फिर से पढ़नी चाहिए
फर्क बड़ा है, और अफसोस कि यह item original list में आने जितना universal नहीं है
SIGHUP पर react करने वाले long-running processes आम तौर पर control TTY के बिना detached चल रहे होते हैं, इसलिए उन्हें “terminal program” कहना थोड़ा खिंचा हुआ होगा
application को सावधान रहना पड़ता है कि वह configuration state के साथ-साथ configuration से derived state को भी गलती से cache न कर बैठे, वरना दोनों mismatch हो जाते हैं
simple apps में यह आसान हो सकता है, लेकिन जिन ज़्यादातर apps को config file चाहिए होती है, वे इतनी simple नहीं होतीं