متغیر محیطی در لینوکس: پیکربندی فرایند بدون سختکد
مفهوم environment variable، تفاوت با متغیر شل، export، env، فایلهای session و نکات امنیتی secret در لینوکس.
بنیانگذار و مهندس محصول

برنامه باید بداند به کدام دیتابیس وصل شود، زبان رابط چیست، و آیا در حالت debug است — بدون اینکه اینها داخل کد قفل شوند. متغیر محیطی (environment variable) جفت نام=مقدار است که فرایند پدر به فرایند فرزند به ارث میدهد و یکی از رایجترین کانالهای پیکربندی در سرور، کانتینر و CI است.
اشتباه گرفتن متغیر محلی شل با متغیر محیطی صادرشده، و ریختن secret در محیط بدون کنترل دسترسی، دو منبع باگ و حادثهاند. PATH موضوع مقالهٔ بعدی است؛ اینجا مدل کلی محیط را میبندیم.

پاسخ کوتاه
دیدن: `printenv` یا `env` یا `echo "$HOME"`. تنظیم برای فرایند فعلی و فرزندان: `export NAME=value`. فقط برای یک فرمان: `NAME=value cmd`. متغیر بدون export به فرزند ارث نمیرسد. برای اسرار، محیط بهتر از硬کد است ولی کامل نیست — فایل مجوزدار، secret manager، یا تزریق در orchestration امنتر از تاریخچهٔ شل و ایمیج لایهدار است.
محیط قرارداد پیکربندی است نه گاوصندوق؛ هر کسی با دسترسی به فرایند میتواند آن را بخواند.
متغیر شل در برابر محیط
bash
MYLOCAL=hello export MYEXPORTED=hello bash -c 'echo local=[$MYLOCAL] exp=[$MYEXPORTED]'
فرزند فقط MYEXPORTED را میبیند. در اسکریپتهایی که سرویس را صدا میزنند، فراموش export یعنی «روی ماشین من کار میکرد» چون در جلسهٔ تعاملی دستی export کرده بودید.
دیدن و فیلتر کردن
bash
printenv printenv HOME env | sort | head env | grep -i proxy
خروجی میتواند secret داشته باشد؛ در اسکرینشات و تیکت عمومی مراقب باشید. برای عیبیابی پروکسی و زبان (`LANG`/`LC_*`) همین فیلترها روزمرهاند.
تنظیم موقت و دائم
- موقت یک فرمان: `DATABASE_URL=... ./app`.
- جلسهٔ فعلی: `export DATABASE_URL=...`.
- دائم کاربر: فایلهای شل مانند ~/.bashrc یا ~/.profile (مقالهٔ ۱۷۰).
- دائم سیستم/سرویس: unit فایل systemd با Environment= یا EnvironmentFile=.
- کانتینر: بخش environment در Compose/K8s — نه لایهٔ ایمیج با secret.
bash
export APP_ENV=staging APP_ENV=staging ./bin/server
نامگذاری و قرارداد
عرف رایج: حروف بزرگ و زیرخط (`MYAPP_DB_HOST`). بعضی فریمورکها پیشوند اجباری دارند. از فاصله در نام پرهیز کنید. مقدار دارای فاصله را نقلقول کنید:
bash
export GREETING='hello world' export JSON_CFG='{"a":1}'
پاک کردن و جلوگیری از ارث
bash
unset MYEXPORTED env -i HOME="$HOME" PATH="$PATH" bash --noprofile --norc env -u HTTP_PROXY curl -sS https://example.com/ | head
env -i محیط تقریباً خالی میسازد — برای تست «آیا به متغیر پنهان وابستهام؟» عالی است. در CI گاهی محیط آلوده باعث سبز/قرمز شدن تصادفی میشود.
فایل .env و مرز مسئولیت
فایلهای dotenv برای توسعه محلی رایجلاند؛ آنها را commit نکنید اگر secret دارند. بارگذاری باید صریح باشد (ابزار یا کتابخانه). روی سرور production، ترجیح با secretهای orchestration است نه کپی .env روی دیسک مشترک.
خواندن محیط از دید فرایند
bash
pid=$(pgrep -n sshd || true) # مثال آموزشی — مسیر دقیق به مجوز وابسته است: tr '\0' '\n' < /proc/self/environ | head
هر فرایند environ خودش را دارد. با دسترسی کافی میتوان محیط فرایند دیگر را دید — دلیل دیگری که توکن در محیط فرایند عمومی خطرناک است.
جدول متغیرهای رایج
| نام | نقش تقریبی |
|---|---|
| HOME | خانهٔ کاربر |
| USER / LOGNAME | نام کاربر |
| PATH | جستوجوی فرمانها |
| LANG / LC_* | محلیسازی |
| EDITOR / VISUAL | ادیتور پیشفرض |
| http_proxy / HTTPS_PROXY | پروکسی |
| TERM | نوع ترمینال |
اشتباههای رایج
- فراموش export و تعجب از خالی بودن در سرویس فرزند.
- چاپ env در لاگ عمومی.
- گذاشتن secret در Dockerfile بهصورت ENV (لایهٔ ایمیج).
- اتکا به .bashrc برای cron/systemd که آن فایل را نمیخوانند.
- فاصله دور = مثل `export A = B` که در شل خطا میدهد.
systemd و محیط سرویس
bash
systemctl show myapp.service -p Environment -p EnvironmentFiles # در unit: # Environment=NODE_ENV=production # EnvironmentFile=-/etc/myapp/env
سرویسها جلسهٔ تعاملی شما نیستند؛ آنچه در ترمینال export کردهاید به unit نمیرسد مگر صریح تزریق شود.
کانتینر و ۱۲عاملی
متدولوژی ۱۲عاملی پیکربندی را در محیط تشویق میکند. در عمل: متغیرهای غیرحساس در مانیفست، حساس در secret mount. بازسازی ایمیج برای عوض کردن URL دیتابیس ضدالگو است.
عیبیابی «روی سرور کار نمیکند»
- همان کاربر و همان روش اجرا (systemd در برابر ssh تعاملی) را مقایسه کنید.
- printenv را در هر دو مسیر (با احتیاط secret) مقایسه کنید.
- PATH و cwd را چک کنید.
- فایل env سرویس و Access کنترل را ببینید.
ارثبری و exec
وقتی فرایندی با exec جایگزین میشود، محیط معمولاً همان میماند مگر صریح عوض شود. در اسکریپتهای wrapper که در انتها exec میکنند، exportهای لازم را قبل از exec بگذارید.
bash
export APP_ENV=production exec ./bin/server
تعارض نام با متغیرهای شل خاص
نامهایی مثل `RANDOM`، `SECONDS`، `PWD` در bash معنای ویژه دارند. برای پیکربندی اپ از پیشوند اختصاصی استفاده کنید تا با builtins و متغیرهای خاص برخورد نکنید.
مشاهده در کانتینر در حال اجرا
bash
docker exec myapp printenv | sort | head # یا در kubernetes با ابزار معادل روی pod
آنچه در مانیفست نوشتهاید باید با آنچه فرایند میبیند یکی باشد؛ اختلاف معمولاً از لایهٔ اشتباه، secret mount، یا override محلی میآید. secret را در تیکت پیست نکنید.
لایهبندی پیکربندی
ترتیب پیشنهادی ذهنی: پیشفرض داخل برنامه < فایل پیکربندی < متغیر محیطی < پرچم خط فرمان. محیط برای تفاوت بین staging و production عالی است؛ برای ساختار تودرتوی بزرگ، فایل را ترجیح دهید و فقط کلید انتخاب محیط را در env بگذارید.
این لایهبندی جلوی انفجار تعداد متغیرها را میگیرد. وقتی ۵۰ متغیر در Compose دیدید، احتمالاً وقت جمعکردن به فایل و secretهای کمتر است.
bash
export APP_ENV=staging ./bin/server --config /etc/myapp/${APP_ENV}.toml
خلاصه
متغیر محیطی کانال پیکربندی ارثی بین فرایندهاست. export را بفهمید، بین جلسهٔ تعاملی و سرویس تفاوت بگذارید، secret را در تاریخچه و ایمیج رها نکنید، و برای عیبیابی محیط واقعی همان فرایند در حال اجرا را ببینید. PATH را جداگانه جدی بگیرید.
سوالات متداول
آیا محیط بین کاربران مشترک است؟
خیر؛ هر جلسه/فرایند مجموعهٔ خودش را دارد، هرچند مقادیر پیشفرض از فایلهای سیستم بیایند.
تفاوت printenv و env؟
هر دو محیط را نشان میدهند؛ env همچنین میتواند با محیط تغییریافته فرمان اجرا کند.
چطور مقدار دارای خط جدید را نگه دارم؟
سخت و شکننده است؛ ترجیحاً از فایل یا base64 با قرارداد مشخص استفاده کنید تا شل نشکند.
منابع و مراجع
- environ(7) — Linux manual page: https://man7.org/linux/man-pages/man7/environ.7.html
- Bash Reference Manual — Environment: https://www.gnu.org/software/bash/manual/html_node/Environment.html
- env(1): https://man7.org/linux/man-pages/man1/env.1.html
- printenv(1): https://man7.org/linux/man-pages/man1/printenv.1.html
- systemd.service Environment directives: https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html
نویسنده
سهیل ابراهیمپور بنیانگذار FutureForge است. روی طراحی محصول، معماری و استقرار نرمافزار سفارشی کار میکند.
یادداشتهای مرتبط
اگر در انتخاب معماری یا مسیر توسعه مطمئن نیستید، میتوانید درباره پروژه صحبت کنیم.
مسئله و محدودیت را بنویسید. اگر تطابق داشته باشیم، برای گفتگو هماهنگ میکنیم.




