- सॉफ़्टवेयर तेज़ी से विकसित हुआ है, लेकिन ऑपरेटिंग सिस्टम की environment variable system अब भी दशकों पुरानी संरचना को बनाए हुए है
- environment variables global string dictionary के रूप में होते हैं, जिनमें namespace या type जैसी कोई सरल संरचना नहीं होती
- Linux में environment variables
execve system call के जरिए parent process से child process तक पहुँचाए जाते हैं
- Bash, glibc, Python आदि environment variables को क्रमशः hashmap, array, dictionary wrapping के रूप में संभालते हैं
- POSIX standard नामों में केवल uppercase की अनिवार्यता नहीं रखता, और व्यवहार में lowercase नामों के उपयोग की भी सिफारिश की जाती है, यानी नियम काफ़ी लचीले हैं
environment variables क्या हैं
- प्रोग्रामिंग भाषाएँ तेज़ी से विकसित हुई हैं, फिर भी ऑपरेटिंग सिस्टम द्वारा दिए गए process execution के आधारभूत ढाँचे, खासकर environment variables वाला हिस्सा, लगभग बदले बिना बना हुआ है
- application चलाते समय अलग फ़ाइल या IPC के बिना runtime parameters पास करने हों, तो वास्तविकता यह है कि environment variables आधारित interface का ही सहारा लेना पड़ता है
- environment variables बिना namespace, बिना type वाली, flat string dictionary की भूमिका निभाते हैं
environment variables के निर्माण और डिलीवरी संरचना
- environment variables processes के बीच values पहुँचाने का पारंपरिक तरीका हैं, और parent process जब child process चलाता है, तो इन्हें साथ भेजा जाता है
- यानी यह parent process से child process में inherit होने वाली संरचना है
- Linux में
execve system call executable file, arguments, और environment variable array (envp) को parameters के रूप में लेता है
- यदि execution command
ls -lah हो, तो
- filename:
/usr/bin/ls
- argv:
['ls', '-lah']
- envp:
['PATH=...','USER=...']
- parent process child को मौजूदा environment ज्यों का त्यों दे सकता है, या पूरी तरह नया environment बना सकता है
- लगभग सभी tools (Bash, Python का
subprocess.run, C library का execl आदि) environment variables को वैसे ही पास कर देते हैं
- अपवादस्वरूप,
login जैसे कुछ tools नया environment बनाते हैं
environment variables कहाँ stored होते हैं और अंदरूनी प्रोसेसिंग
- kernel program शुरू होने पर environment variables को stack पर null-terminated string के रूप में store करता है
- इस data को program के लिए सीधे modify करना कठिन होता है, इसलिए आम तौर पर program इसे copy करके अपनी internal structure में manage करता है
- अलग-अलग languages और shells में environment variables को store करने का तरीका
- Bash: stack-structured hashmap (dictionary) के रूप में manage करता है
- हर function call पर local scope का map बनता है
- केवल
export की गई variables ही child process तक जाती हैं
local से घोषित variables भी export के जरिए child process तक भेजी जा सकती हैं
- उदाहरण:
export PATH के जरिए local बदलाव child तक दिखाया जा सकता है, लेकिन global पर असर नहीं पड़ता
- glibc(C library) :
environ नाम की dynamic array संरचना को putenv, getenv के जरिए manage करती है
- array structure होने के कारण lookup और update दोनों की linear time complexity होती है
- इसलिए high-performance data storage के लिए यह उपयुक्त नहीं है
- Python: अंदर
os.environ के जरिए dictionary जैसा interface देता है, लेकिन वास्तव में यह C library की environ array से linked होता है
os.environ में value बदलने पर os.putenv कॉल होता है, जिससे C library में भी बदलाव दिखता है
- उल्टी दिशा में sync नहीं होता, इसलिए one-way behavior मौजूद है
environment variables का format और अनुमति की सीमा
- Linux kernel और glibc environment variable format के प्रति बहुत उदार हैं
- एक ही नाम के कई entries होकर multiple values मौजूद हो सकती हैं
= के बिना भी register किया जा सकता है, और emoji जैसी special characters पर भी कोई रोक नहीं है
- उपलब्ध size limits
- individual variable: 128 KiB (आमतौर पर x64 environment में)
- total sum: 2 MiB (command-line arguments के साथ साझा)
- environment variables पर stack space के 1/4 से अधिक न होने की सीमा लागू होती है
environment variables की विशेषताएँ और edge cases
- Bash असामान्य environment variables (duplicate,
= के बिना entries आदि) के मामले में duplicate नाम हटाता है और invalid entries को नज़रअंदाज़ करता है
- यदि variable name में space हो, तो Bash उससे reference नहीं कर पाता, लेकिन वह अब भी child process को भेजा जा सकता है
- उदाहरण: Nushell, Python आदि space वाले नाम की variables बना सकते हैं
- Bash ऐसी entries को अलग hashmap (
invalid_env) में रखकर manage करता है
standard environment variable format और naming rules
- POSIX standard के अनुसार नाम में equal sign (
=) न हो, तो उसे variable माना जा सकता है
- आधिकारिक recommendation: नाम में केवल uppercase, numbers, underscore हों (पहला character digit न हो)
- lowercase variables application-specific namespace के लिए मानी जाती हैं
- standard tools uppercase का उपयोग करते हैं, लेकिन lowercase variables की भी अनुमति है
- व्यवहार में developers ज़्यादातर ALL_UPPERCASE naming style का उपयोग करते हैं
- recommended rule: variable names के लिए regex
^[A-Z_][A-Z0-9_]*$ और values के लिए UTF-8 का उपयोग
- यदि exceptions या compatibility की चिंता हो, तो POSIX Portable Character Set (ASCII) उपयोग करने की सिफारिश है
निष्कर्ष
- environment variables अब भी पुराना लेकिन अनिवार्य interface हैं, जो ऑपरेटिंग सिस्टम और applications के बीच boundary layer की भूमिका निभाते हैं
- संरचनात्मक सीमाओं के बावजूद Bash, C, Python आदि इन्हें अलग-अलग तरीक़ों से wrap करके उपयोग कर रहे हैं
- आधुनिक systems में स्पष्ट namespace और type system वाले configuration management की आवश्यकता लगातार बढ़ रही है
2 टिप्पणियां
ऊपरी तौर पर इसका महत्व कम होता दिखा था, लेकिन Docker और cloud के आने के बाद यह फिर से ऐसा बन गया है जिससे बचना नामुमकिन है।
Hacker News राय
मैं SRE/Sysadmin/DevOps/Whatever के रूप में काम करता हूँ, और ब्लॉग में मैंने env vars के standardization पर सिर्फ आसान बातें की थीं, लेकिन मैं यह बताना चाहता हूँ कि alternatives भी लगभग उतनी ही झुंझलाहट पैदा करते हैं, खासकर जब secrets शामिल हों
अगर application को Hashicorp Vault/OpenBao/Secrets Manager जैसे किसी खास secret store (vault) तक पहुँचने के लिए बनाया जाए, तो जल्दी ही गंभीर vendor lock-in पैदा हो जाता है, और उसे बदलना library स्तर तक फैलकर बहुत मुश्किल हो जाता है
Vault की availability बहुत critical हो जाती है, और जब upgrade या maintenance की ज़रूरत पड़े तो ops team बुरी तरह फँस जाती है
अगर config file के ज़रिए secret दिया जाए, तो उसमें secret कैसे रखा जाए यह खुद मुश्किल है, क्योंकि config file अक्सर public path पर होती है
आख़िरकार या तो "privileged system app को देने से पहले template substitution करे" या "पूरी config file को secret store में रखकर app तक पहुँचाए" — इन्हीं में से किसी एक पर निर्भर होना पड़ता है
Template का काम गलती-प्रवण होता है, और पूरी config file को secret store में ले जाते समय भी किसी के गलत upload कर देने का जोखिम रहता है, जो काफ़ी तनाव पैदा करता है
आजकल ज़्यादातर systems containers पर चलते हैं, और अगर कंपनी infrastructure hygiene अच्छी तरह maintain नहीं करती, तो config file हमेशा अजीब जगहों पर होती है, जिससे mount process और ज़्यादा उलझनभरा हो जाता है और गलतियाँ बार-बार होती हैं
JSON/YAML/TOML, कोई भी format इस्तेमाल करें, अपने-अपने अनोखे bugs रोज़मर्रा की बात हैं; उदाहरण के लिए YAML का Norway problem है
मैंने Kubernetes Secrets API के ज़रिए secret लेने का तरीका भी देखा है, लेकिन यह भी मज़बूत vendor lock-in की समस्या से टकराता है
जब तक आप operator जैसी कोई विशेष system design नहीं कर रहे हों, मैं इस approach की सक्रिय रूप से सिफ़ारिश नहीं करता
Subprocess के ज़रिए env vars set करने की प्रक्रिया में आने वाली समस्याएँ भी देखी हैं, लेकिन मुझे लगता है कि आजकल teams इसकी बजाय message bus आधारित systems इस्तेमाल करती हैं, जो ज़्यादा robust होते हैं और independent scaling की सुविधा देते हैं
हमारी team ने एक हल्की, general-purpose Secrets library बनाई थी, और पीछे AWS Secrets Manager जैसे vendor-specific backends को plugin की तरह जोड़ा था
उसमें local cache configuration और per-parameter cache bypass options थे, इसलिए असली vendor-specific logic सिर्फ backend में रहती थी और library व application vendor-dependent नहीं होते थे
जब Vault पर जाना पड़ा, तब सिर्फ एक backend जोड़ा और config बदली, और सब बिना किसी बड़ी दिक्कत के चल गया
मैं जानना चाहता हूँ कि Kubernetes secret API को vendor lock-in समस्या की तरह क्यों देखा जा रहा है
क्या यह ऐसा मामला था जहाँ deployment yaml को Kubernetes deployment के अलावा किसी और उद्देश्य के लिए इस्तेमाल करना था?
ज़्यादातर apps में secret को container में mount करके, फिर env var या json file के रूप में app में inject कर दें, तो app environment-independent तरीके से पढ़-लिख सकता है
जहाँ तक मुझे पता है, etcd backend encryption को KMS के साथ configure भी किया जा सकता है
मुझे भी ठीक से समझ नहीं आता कि Kubernetes Secrets API के ज़रिए secret लेने को lock-in क्यों कहा जा रहा है
मूल रूप से K8s secrets encrypted form में store नहीं होते, इसलिए मेरा मानना है कि इसका अर्थ तभी बनता है जब (0) आप K8s इस्तेमाल कर रहे हों, (1) control plane पर encryption configure किया हो, और (2) CSI driver जैसी अतिरिक्त solution भी ज़रूर इस्तेमाल कर रहे हों
और Secret Store CSI Driver तो Conjur सहित कई backends को support करता है, इसलिए lock-in की बात उलटी लगती है
इन्हीं वजहों से मैं अभी भी config के लिए env vars और dotenv का ही ज़्यादा इस्तेमाल करता हूँ
env var आधारित configuration structure बहुत simple है, और secret managers जैसे कई tools के साथ अच्छी compatibility रखता है
पिछले कुछ सालों में YAML आधारित sOps में मेरी थोड़ी-थोड़ी दिलचस्पी बढ़ी है
YAML app configuration structure को बहुत intuitive तरीके से व्यक्त करता है, और sops के साथ उसका सिर्फ कुछ हिस्सा encrypt करके manage करना आसान है
हालाँकि GPG key management थोड़ा मुश्किल हो सकता है, लेकिन Vault या OpenBao जैसी चीज़ों से इसे हल किया जा सकता है
बस, उस process में फिर vendor lock-in की समस्या आ जाती है, हालाँकि OpenBao में यह शायद कुछ कम है
command execution result से भी env vars लिए जा सकते हैं, इसलिए templating के बिना भी vendor lock-in से बचा जा सकता है
एक और दिलचस्प बात: POSIX में setenv() मूल रूप से टूटा हुआ है, इसलिए मेरा मानना है कि library code में इसे कभी इस्तेमाल नहीं करना चाहिए
जब app code में इसका इस्तेमाल करना ही पड़े, तब भी यह आख़िरी विकल्प होना चाहिए, और इसे thread बनाने से पहले ही इस्तेमाल करना चाहिए
getenv() env var के मूल pointer को सीधे लौटा देता है, इसलिए जब setenv() variable overwrite करता है तो कोई protection नहीं होती
बहुत सावधानी रखनी चाहिए
env vars को ठीक से set करना हो तो मेरा मानना है कि execve() के साथ set करना सही तरीका है
यह तरीका तभी उपयुक्त है जब exec() के पहले/बाद env vars के ज़रिए जानकारी pass करनी हो
मुझे समझ नहीं आता कि library code में setenv का इस्तेमाल क्यों करना चाहिए
Solaris ने इस समस्या को हल कर लिया था, लेकिन Linux अभी भी वही पुराना तरीका पकड़े हुए है
NetBSD में getenv_r() नाम का सुरक्षित विकल्प बहुत पहले से है, और हाल में FreeBSD ने भी इसे अपनाया है
macOS भी शायद जल्द ही इसका अनुसरण करेगा
glibc या POSIX में इसे जोड़ने की कोशिश पहले भी हुई थी, लेकिन उसे ठुकरा दिया गया था
अगर यह कई platforms पर फैल गया, तो उम्मीद है कि कभी न कभी इसे आधिकारिक रूप से भी स्वीकार कर लिया जाएगा
NetBSD getenv_r दस्तावेज़
FreeBSD commit
env vars का इस्तेमाल secrets देने के लिए अक्सर किया जाता है, लेकिन मुझे नहीं लगता कि यह बहुत अच्छी practice है
Linux में एक ही user के रूप में चल रहे सभी processes एक-दूसरे के env vars देख सकते हैं
आप threat model जैसा भी रखें, खासकर developer systems पर, एक ही user के तहत चलने वाले processes इतने ज़्यादा होते हैं कि यह चिंता की बात है
LLM agents जैसे मामलों में, जहाँ container के बाहर कई processes घूम रहे हों, यह issue और गंभीर हो जाता है
इसके अलावा env vars आमतौर पर child processes तक भी उसी तरह चले जाते हैं, इसलिए जब secret सिर्फ एक process को चाहिए हो तब भी वह अनावश्यक रूप से फैल जाता है
systemd env vars को DBUS के ज़रिए सभी system clients को दिखाता है, और आधिकारिक docs में भी env vars में secret न रखने की चेतावनी है
अगर यह सच है, तो इसका मतलब है कि root-only unit पर set किया गया env var भी सामान्य users को दिखाई दे सकता है, और यह बहुत से system administrators के लिए काफ़ी चौंकाने वाली बात होगी
आख़िरकार मेरा मानना है कि सिर्फ वही ढाँचा, जहाँ secret manager temporary file sharing के ज़रिए secret पास करे (जैसे 1Password का op cli, flask, terraform आदि), env vars और plain-text files के exposure से सचमुच बचा सकता है
systemd का credentials system भी ऐसा ही ढाँचा है, लेकिन support अभी बहुत सीमित है
अगर किसी को env vars या plain-text files के बिना secret pass करने का अच्छा तरीका पता हो, तो वह साझा करे
संदर्भ के लिए, 1Password op client के मामले में मुझे यह सुरक्षित लगता है क्योंकि हर session में मेरी approval चाहिए होती है; अगर कोई malicious process op binary call करे, तब भी अलग approval चाहिए
अब बचा हुआ सवाल यह है कि उस secret को असल में जिस process को ज़रूरत है, उसे कैसे दिया जाए — और ऐसा लगता है जैसे हम फिर वहीं लौट आते हैं
systemd env vars आधिकारिक दस्तावेज़ लिंक
लगभग 2012 से env vars भी सामान्य memory जितने ही सुरक्षित हो गए हैं
संबंधित commit रिकॉर्ड
किसी दूसरे process के env vars पढ़ने के लिए ptrace permission अनिवार्य है, और अगर ptrace से पढ़ना संभव है तो वैसे भी सारे secrets पढ़े जा सकते हैं, इसलिए यह चिंता अर्थहीन है — ऐसा तर्क है
command-line जानकारी (cmdline) अलग मामला है, लेकिन env vars अब इस तरीके से आसानी से expose नहीं होते
अधिकांश operating systems के security model में, किसी एक user के रूप में चलने का मतलब लगभग यह है कि आपने उस user के सारे अधिकार दे दिए
अपवाद के तौर पर FreeBSD का capsicum, Linux का landlock, SELinux, AppArmor, Windows का integrity label जैसी अतिरिक्त security सुविधाएँ हैं, लेकिन ज़्यादातर की सीमाएँ साफ़ हैं
अंततः मैं अपने processes को kill, pause या debug करने के लिए स्वतंत्र हूँ, और ptrace/process_vm_readv/ReadProcessMemory वगैरह से अपने स्वामित्व वाले process के secrets तक कभी भी पहुँचा जा सकता है
पूरी तरह अलग security models भी हैं, जैसे पूरी capability-based OS, लेकिन अधिकांश systems यही model अपनाते हैं, इसलिए उसकी सीमाओं और ज़िम्मेदारियों को समझना चाहिए
env vars या plain-text files का उपयोग किए बिना secret pass करने के अच्छे तरीकों में memfd_secret दिमाग में आता है
memfd_secret man page
language या framework स्तर पर support ज़्यादा नहीं है, इसलिए खासकर Rust में, या शायद Go में भी, FFI के ज़रिए इसे आज़माया जा सकता है
मैंने PHP में इसे सीधे wrap करने के बारे में सोचा था, लेकिन php-fpm तक modify नहीं करना चाहता था, इसलिए वहीं रुक गया
व्यवहार में, अगर process manager पहले से secret file descriptor खोलकर child process को दे दे, और उसे memory वगैरह में expose किए बिना इस्तेमाल किया जा सके, तो वही सबसे सुरक्षित होगा
पारंपरिक Unix security model आज भी थोड़े-बहुत सुधारों के साथ व्यापक रूप से इस्तेमाल होता है, लेकिन सस्ते computing environments या आधुनिक परिस्थितियों में इसकी सीमाएँ स्पष्ट हैं
अगर secrets को दूसरे processes से छिपाना ज़रूरी है, तो मूल उपाय यही है कि उन्हें अलग user के तहत चलाया जाए
या फिर remote access वाला तरीका अपनाया जा सकता है, लेकिन उसके साथ भी अपने नुकसान और complexity आते हैं
आजकल container platforms में config या secret देने के लिए env vars की सिफ़ारिश की जाती है
container के अंदर दूसरे processes env vars नहीं देख सकते, ऐसा design किया गया है
child processes को env vars inherit होना भी design का हिस्सा है, क्योंकि environment configure करने वाला पक्ष ही secret value रखने वाला होता है और वही उस environment को सीधे set करता है
जिन मुद्दों की चिंता की जा रही है, उनमें से ज़्यादातर मुझे बड़ी समस्या नहीं लगते; ज़रूरत हो तो मैं specifics पर बात करने को तैयार हूँ
बहुत-सी टिप्पणियाँ secret management और उसकी समस्याओं पर केंद्रित हैं, लेकिन env vars के फ़ायदों पर भी एक बार सोचना चाहिए
env vars Unix processes को संरचनात्मक रूप से जोड़ने वाले "अनिश्चित scope वाले, dynamic extent variable bindings" हैं
इन्हें सिर्फ साधारण text files से सीधे तुलना करने के बजाय, यह याद रखना चाहिए कि env vars का अस्तित्व child processes को सुरक्षित रूप से context देने के लिए है
जितनी जटिल process structure होगी — जैसे nested shells या जटिल programs के subprocesses — उतना ही env vars की भूमिका चमकती है
मैं Varlock को सचमुच उपयोगी मानते हुए recommend करना चाहूँगा
यह project में आवश्यक env vars में कौन-से required हैं, कौन-से optional, उनका data type क्या है, और उन्हें कहाँ से लाना है — यह सब साफ़ परिभाषित करता है और manage करना आसान बनाता है
Varlock आधिकारिक साइट
व्यावहारिक अनुभव से कहूँ, तो env vars कितने जटिल हो सकते हैं, इसका एक उदाहरण है: पिछली कंपनी में मैं यह debug करने में पूरी तरह भटक गया था कि एक खास ENV variable आख़िर set कहाँ हो रहा है
शुरू में लगा था कि वह .bashrc या किसी एक आसान जगह पर set होगा, लेकिन असल में वह company-wide, region, business unit, team, individual आदि मिलाकर कम-से-कम 10 layers के जरिए set हो रहा था
आख़िर में bash debug flags चालू करने के बाद ही मैं एक-एक करके पता लगा पाया कि वह कहाँ set हो रहा था
मुझे नहीं पता दूसरी languages भी support करती हैं या नहीं, लेकिन Node.js ने हाल ही में env vars की access और mutation को ठीक-ठीक trace करने वाला command-line flag जोड़ा है
Node.js --trace-env दस्तावेज़
इतने सारे APIs के ज़रिए values set/modify हो सकती हैं कि जटिल debugging में यह बहुत काम का लगता है
यह वैसा मामला है जहाँ सोच आता है: "क्या एक namespace काफ़ी नहीं होना चाहिए?"
मैंने बहुत पहले env vars का इस्तेमाल छोड़ दिया था
अब मैं compiler के साथ dmd.conf file रखता हूँ, और compiler उसी file को सीधे पढ़ता है
env vars की समस्याओं में सबसे गंभीर उनकी implicit और opaque प्रकृति है
*nix दुनिया में ज़्यादातर apps env vars पर निर्भर रहने की प्रवृत्ति रखते हैं
भले ही explicit और transparent configuration methods — जैसे config file, remote service, या command-line arguments — अतिरिक्त रूप से supported हों, env vars का support इस दुनिया की परंपरा है
आख़िरकार env vars भी एक global hash map ही हैं, जो child processes के लिए clone और extend होते हैं; 1979 में यह समझदारी भरा design रहा होगा, लेकिन आज यह कई बार उल्टा नुकसानदेह हो जाता है
उदाहरण के लिए Kubernetes default रूप से "service link" env vars के ज़रिए container environment को प्रदूषित करता है
अगर app द्वारा अपेक्षित env vars और default env vars में टकराव हो जाए, तो debugging बेहद मुश्किल हो जाती है
Kubernetes आधिकारिक दस्तावेज़ संदर्भ
इसके अलावा /bin, /usr/bin, /lib, /usr/lib जैसी पुरानी संरचनाओं को बिना सवाल जारी रखने की आदत भी बहुत दिखती है
संदर्भ: legacy directories बनाए रखने पर Ubuntu Q&A
vi में hjkl की उत्पत्ति 40 साल पुराने dumb terminal से हुई थी, जिसकी बिक्री भी बहुत कम थी
(Nokia N9 से भी कम)
Linux में हर बार env vars set करते समय मुझे घबराहट होती है
आधिकारिक रूप से काम करने वाला तरीका distributions के हिसाब से थोड़ा अलग होता है, और online guides के अनुसार करने पर भी reboot या terminal बंद होने पर सब गायब हो जाता है
काश Windows की तरह कोई आसान global GUI env var editor होता
Windows में changes लागू करने के लिए नया terminal खोलना पड़ता है, यह झंझट है, लेकिन उसके अलावा वह हमेशा ठीक से काम करता है
env vars session बदलने पर स्वाभाविक रूप से बने नहीं रहते, इसलिए उन्हें ऐसी जगह लिखना पड़ता है जो हर session में दोबारा execute हो — जैसे login/terminal — और यही सामान्य है
login पर .bash_profile चलता है, और child sessions में .bashrc
अगर .bash_profile से .bashrc को source करा दिया जाए, और अधिकतर settings .bashrc में रखी जाएँ, तो manage करना आसान होता है
अगर आप Bash नहीं बल्कि zsh/fish जैसी दूसरी shell इस्तेमाल करते हैं, तो उसी shell के अनुसार setup करना होगा
Linux में ऐसा कोई आधिकारिक और एकीकृत GUI नहीं है जो हर terminal पर env vars लागू कर दे
जटिल parsing GUI बनाना संभव है, लेकिन सीधे text editor से बदलना ज़्यादा आसान है
जो व्यक्ति मुख्य रूप से Linux इस्तेमाल करता है, उसके नज़रिए से Windows का यह व्यवहार उल्टा ज़्यादा असुविधाजनक लगता है
बहुत सारे apps env vars को प्रदूषित कर देते हैं, और जब कुछ काम नहीं करता, तो अक्सर पता चलता है कि $SOFTWARE किसी अजीब folder से चल रहा था — यानी भारी गड़बड़
अगर आप systemd इस्तेमाल करते हैं, तो /etc/environment या /etc/environment.d/ में KEY=VALUE लिखने का तरीका भी है
वास्तव में इसके लिए GUI भी बनाया जा सकता है
लेकिन env vars को चल रहे process में inject नहीं किया जा सकता; उन्हें लागू करने के लिए restart करना पड़ता है, यही इसकी सीमा है
systemd आधिकारिक दस्तावेज़ संदर्भ
xkcd Standards कॉमिक
Linux में env vars set करने के पहले से 14 प्रतिस्पर्धी तरीके होने की स्थिति में, अगर आप कहें "चलो इसे एक में standardize कर दें", तो अगले दिन 15 standards हो जाते हैं — यह उसी को मज़ेदार ढंग से दिखाता है
env vars से जुड़ा मेरा पसंदीदा trivia यह है कि PS1 जैसी चीज़ें, जिन्हें हर कोई env var समझता है, वास्तव में env vars नहीं बल्कि shell variables हैं
PS1 को "env" command से देखा भी नहीं जा सकता