متغیر PATH در لینوکس: شل فرمان را از کجا پیدا میکند؟
مفهوم PATH، ترتیب دایرکتوریها، which/type، افزودن امن مسیر و خطر PATH hijacking در لینوکس.
Founder & product engineer

پیام `command not found` اغلب به معنای «برنامه نصب نیست» نیست؛ یعنی شل در هیچکدام از دایرکتوریهای فهرستشده در PATH فایلی اجرایی با آن نام ندیده است. PATH یکی از مهمترین متغیرهای محیطی است چون مرز بین «فرمان در دسترس» و «باید مسیر کامل بنویسی» را تعیین میکند.
فهم ترتیب جستوجو جلوی نصبهای تکراری، سایهافتادن باینری اشتباه، و حملههای سادهٔ PATH hijacking را میگیرد.

پاسخ کوتاه
PATH لیست دایرکتوریهای جداشده با `:` است که شل بهترتیب برای یافتن فرمان میپیماید. ببینید با `echo "$PATH"`. کدام باینری انتخاب میشود: `type -a name` یا `command -v name`. برای افزودن مسیر کاربر: معمولاً در ابتدای PATH در فایل شل، با مسیر مطلق. هرگز `.` را بیدلیل به PATH اضافه نکنید. پس از تغییر در جلسه، گاهی `hash -r` لازم است.
اولین تطبیق برنده است؛ ترتیب PATH سیاست است نه جزئیات تزئینی.
شکل PATH
bash
echo "$PATH" printenv PATH tr ':' '\n' <<< "$PATH"
نمونههای رایج: `/usr/local/bin`، `/usr/bin`، `/bin`، و مسیرهای کاربر مثل `~/.local/bin`. خالی بودن عنصر (مثل `::` یا شروع/پایان با `:`) در بعضی شلها معنای خطرناک «دایرکتوری فعلی» میدهد — از ساختن چنین PATHی پرهیز کنید.
کدام باینری؟ which در برابر type
bash
type python3 type -a python3 command -v python3 ls -l $(command -v python3)
در bash، `type` builtin است و alias/function را هم میفهمد؛ `which` خارجی گاهی سادهتر و گاهی گمراهکننده است. برای اسکریپت قابلحمل، `command -v` توصیهٔ رایجی است.
سایه افتادن (shadowing)
اگر `/usr/local/bin/node` قبل از `/usr/bin/node` در PATH باشد، نسخهٔ محلی برنده است. بعد از نصب نسخهٔ جدید، اگر هنوز قدیمی میبینید:
bash
type -a node hash -r type -a node
bash نتایج را cache میکند؛ hash -r کش را پاک میکند.
افزودن مسیر بهصورت امن
bash
# فقط جلسهٔ فعلی: export PATH="$HOME/.local/bin:$PATH" # جلوگیری از تکرار ساده: case ":$PATH:" in *:"$HOME/.local/bin":*) ;; *) export PATH="$HOME/.local/bin:$PATH" ;; esac
مسیر را مطلق بگذارید. افزودن به ابتدا یعنی اولویت بالاتر؛ به انتها یعنی فقط اگر جای دیگر نبود. برای ابزارهای خودتان معمولاً ابتدا؛ برای جلوگیری از سایه انداختن روی سیستم، فکر کنید.
command not found: چکلیست
- آیا بسته نصب است؟ (apt/dnf/…)
- آیا باینری در مسیر غیر استاندارد است؟ مسیر کامل را بیازمایید.
- آیا PATH جلسهٔ فعلی با سرویس/cron فرق دارد؟
- آیا نام را اشتباه تایپ کردهاید یا alias خراب دارید؟
bash
ls /usr/bin/jq echo "$PATH" type jq
PATH در cron و systemd
cron اغلب PATH حداقلی دارد؛ systemd نیز محیط محدودتری از جلسهٔ SSH شما میدهد. اگر اسکریپت در ترمینال کار میکند و در timer نه، اول PATH را در unit یا خود اسکریپت با مسیر مطلق فرمانها درست کنید.
bash
# در اسکریپت مقاوم: PATH=/usr/local/bin:/usr/bin:/bin export PATH
امنیت: PATH hijacking
- دایرکتوری قابلنوشتن توسط دیگران را در PATH نگذارید.
- `.` یا مسیر نسبی مبهم را اضافه نکنید.
- اسکریپتهای root باید به PATH مینیمال و مسیر مطلق فرمانهای حساس تکیه کنند.
اگر مهاجم بتواند فایلی به نام `ls` در دایرکتوریای که زودتر از /bin جستوجو میشود بنویسد و شما آن را اجرا کنید، کنترل به دست او میافتد. این سناریو کلاسیک است.
جدول تصمیم سریع
| علائم | اقدام اول |
|---|---|
| command not found | نصب بسته / اصلاح PATH / مسیر مطلق |
| نسخهٔ غلط اجرا میشود | type -a و ترتیب PATH و hash -r |
| در SSH هست در cron نیست | PATH cron/systemd را ببینید |
| ابزار کاربر دیده نمیشود | ~/.local/bin را به PATH اضافه کنید |
چند نسخه با ابزارهای نسخه (نگاه کوتاه)
nvm، pyenv، asdf و مشابه PATH را پویا عوض میکنند. وقتی «نسخه عوض شد ولی ترمینال هنوز قدیم است»، معمولاً شل جدید یا `hash -r` و بارگذاری دوبارهٔ init لازم است. در CI نسخه را پین کنید نه اینکه به PATH لپتاپ اعتماد کنید.
اشتباههای رایج
- export PATH=/new/bin بدون حفظ PATH قبلی و از دست دادن /bin.
- کپی PATH ویندوزی با ; بهجای :.
- گذاشتن مسیر نسبی.
- ویرایش PATH در فایل اشتباه شل که برای login/non-login خوانده نمیشود.
بازیابی PATH خراب در جلسه
bash
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin hash -r
این حداقل معقول روی بسیاری توزیعهاست؛ سپس فایل پیکربندی را درست کنید تا جلسهٔ بعد تکرار نشود.
PATH و زبانهای چندنسخهای در CI
در CI، بهجای اعتماد به PATH ایمیج پایه، نسخه را با setup action یا تصویر رسمی پین کنید و `command -v` را در ابتدای جاب چاپ کنید. لاگ شروع باید بگوید کدام python/node واقعاً استفاده میشود.
bash
command -v python3 python3 -V echo "$PATH" | tr ':' '\n' | head
دایرکتوریهای استاندارد کاربر
XDG و قرارداد `~/.local/bin` برای ابزارهای pip/user رایج شدهاند. اگر ابزار نصب شده ولی پیدا نمیشود، اول همان مسیر را چک کنید نه اینکه دوباره با sudo در سیستم نصب کنید.
bash
ls -l "$HOME/.local/bin" 2>/dev/null | head export PATH="$HOME/.local/bin:$PATH"
مستندسازی برای همکار
در README بگویید کدام مسیرها باید در PATH باشند و چگونه به فایل شل اضافه شوند. یک بلوک کپیپیست با case جلوگیری از تکرار، بهتر از «PATH را درست کنید» مبهم است.
تشخیص سریع پس از نصب بسته
بعد از apt install گاهی PATH شما از قبل کش شده یا ترمینال قدیمی است. قبل از گزارش باگ بسته:
bash
hash -r command -v toolname dpkg -L packagename 2>/dev/null | grep -E 'bin/' | head
اگر باینری در /usr/sbin است و PATH کاربر آن را ندارد، یا مسیر را اضافه کنید یا با sudo/مسیر کامل اجرا کنید — بسته به طراحی توزیع.
در مستند داخلی بنویسید کدام ابزارها در sbinاند تا تازهواردها گیج نشوند.
خلاصه
PATH فهرست جستوجوی فرمانهاست و ترتیبش برنده را مشخص میکند. با type/command -v ببینید چه چیزی انتخاب میشود، مسیر را امن و مطلق اضافه کنید، تفاوت محیط cron/systemd را فراموش نکنید، و هرگز PATH را طوری بازنویسی نکنید که سیستمبیسیکها حذف شوند.
سوالات متداول
چرا sudo گاهی فرمان را پیدا نمیکند؟
sudo ممکن است env را پاک یا PATH امن جداگانه استفاده کند. `sudo env PATH="$PATH" cmd` یا تنظیمات sudoers را بفهمید؛ بهتر مسیر مطلق روی اسکریپتهای مدیریتی است.
تفاوت PATH و path؟
در bash معمولاً PATH بزرگحرف استاندارد محیط است؛ برخی شلها آرایهٔ path جدا دارند (مثل zsh).
چطور موقتاً فقط از /usr/bin استفاده کنم؟
`env PATH=/usr/bin:/bin bash --noprofile --norc` برای تست ایزوله.
منابع و مراجع
- environ(7): https://man7.org/linux/man-pages/man7/environ.7.html
- Bash manual — Command Search and Execution: https://www.gnu.org/software/bash/manual/html_node/Command-Search-and-Execution.html
- command(1) / Shell Builtin command -v: https://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html
- sudoers(5) env_reset / secure_path discussion via man sudoers: https://man7.org/linux/man-pages/man5/sudoers.5.html
Author
Soheil Ebrahimpour is the founder of FutureForge. He works on product design, architecture, and getting custom software into production.
Related notes
If you are unsure about architecture or the build path, we can talk about the project.
Describe the problem and the constraints. If there is a fit, we will schedule a conversation.




