لینوکس

نحوه مشاهده و به‌روزرسانی متغیر محیطی PATH در لینوکس

مقدمه

متغیر محیطی PATH در لینوکس، فهرستی از دایرکتوریها—جدا شده با دونقطه—است که شل هنگام اجرای دستور جستجو می‌کند. هر بار که نام دستوری مانند python3، grep یا myapp را وارد می‌کنید، شل دایرکتوریهای PATH را از چپ به راست چک کرده و اولین مورد اجراییِ مطابقت‌یافته را اجرا می‌کند.

در این آموزش، PATH را مشاهده کرده؛ به‌صورت موقت و دائم (در bash و zsh) تغییر می‌دهید؛ تغییرات را تأیید، Entryها را حذف و خرابیهای رایج را عیب‌یابی می‌کنید.

مثالهای این راهنما روی اوبونتو 24.04، دبیان ۱۲ و راکی لینوکس ۹ اعتبارسنجی شده‌اند. دستورات با خروجی مورد انتظار نشان داده شده‌اند تا نتایج‌تان را مقایسه و از اعمال هر تغییر مطمئن شوید.

نکات کلیدی

  • PATH، فهرستی از دایرکتوریها—جدا شده با دونقطه—است که شل هنگام Resolve کردن دستور، از چپ به راست جستجو می‌کند.
  • هر دوی echo $PATH و printenv PATH مقدار فعلی را نمایش می‌دهند.
  • export PATH=$PATH:/new/dir مقدار PATH را فقط برای نشست فعلی تغییر می‌دهد.
  • تغییرات دائم به ~/.bashrc (برای شلهای تعاملی bash)، ~/.zshrc (برای zsh) و /etc/environment (برای مقادیر در-سطح-سیستم) می‌روند.
  • which، type -a و command -v تأیید می‌کنند دستوری به کدام باینری Resolve می‌شود.
  • اعمال تغییرات، یا source ~/.bashrc یا نشست Shell جدیدی لازم دارد.
  • ترتیب مهم است: دایرکتوریهای زودتر فهرستشده در PATH بر دیرترها اولویت دارند.

پیش‌نیازها

  • سیستم لینوکسی اجراکننده bash یا zsh. دستورات روی اوبونتو 24.04، دبیان ۱۲ و راکی لینوکس ۹ اعتبارسنجی شده‌اند.
  • کاربر غیر root با دسترسی sudo. در صورت نیاز راهنمای راه‌اندازی اولیه سرور با اوبونتو در پارمین کلود را ببینید.
  • آشنایی با متغیرهای محیطی. راهنمای «نحوه خواندن و تنظیم متغیرهای محیطی و شل در لینوکس» را در پارمین کلود ببینید.

درک نحوه کار متغیر PATH در لینوکس

PATH چه چیزی شامل و شل چگونه از آن استفاده می‌کند

PATH، مسیرهای مطلق دایرکتوریها—جدا شده با دونقطه—را ذخیره می‌کند. وقتی دستوری را بدون مسیر کامل اجرا می‌کنید، شل هر دایرکتوری را به‌ترتیب بازرسی کرده و اولین فایل مطابقت‌یافته با مجوز اجرا را اجرا می‌کند.

برای بازرسی PATH به‌صورت یک-دایرکتوری-در-هر-خط، این را اجرا کنید:

tr ':' '\n' <<< "$PATH"
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/local/games
/usr/games

اگر نام اجراییِ یکسانی در بیش از یک دایرکتوری وجود داشته باشد، اولین دایرکتوریِ این فهرست برنده می‌شود.

PATH چگونه توسط پروسهها و Subshellها به ارث می‌رسد

پروسههای فرزند، متغیرهای محیطیِ Export-شده را از پروسه والد به ارث می‌برند. متغیر Shell فقط در شل فعلی موجود است—تا وقتی با export علامت‌گذاریش کنید:

MYVAR="hello"
bash -c 'echo $MYVAR'   # چیزی چاپ نمی‌کند

export MYVAR="hello"
bash -c 'echo $MYVAR'   # چاپ می‌کند: hello

PATH هم از همین قاعده پیروی می‌کند.

گام ۱ — مشاهده متغیر PATH فعلی

استفاده از echo برای نمایش PATH

echo $PATH سریع‌ترین راه دیدن اینکه شل‌تان هنگام اجرای دستور کدام دایرکتوریها را جستجو می‌کند، است:

echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games

خروجی، رشته منفردی است که هر دایرکتوری با : جدا شده.

استفاده از printenv برای نمایش PATH

printenv PATH مستقیماً از محیط پروسه می‌خواند—not از طریق بسط Shell؛ که آن را در اسکریپتها و زمینههای غیر-تعاملی قابل-اعتمادتر می‌سازد:

printenv PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games

چون printenv فقط متغیرهای Export-شده را چاپ می‌کند، به‌شکل تمیزی محیطِ به-ارث-رسیده را از متغیرهای محلیِ شل تفکیک می‌کند.

خواندن PATH در زمینه اسکریپت

اسکریپتهایی که با bash script.sh فراخوانی می‌شوند، PATHای متفاوت از شل تعاملی‌تان می‌بینند—چون ~/.bashrc یا ~/.bash_profile را Source نمی‌کنند. این اسکریپت PATHای را که پروسه bashِ غیر-تعاملی واقعاً دریافت می‌کند چاپ می‌کند:

#!/usr/bin/env bash
echo "Script PATH: $PATH"

برای قابل-اعتماد کردن PATH اسکریپت—فارغ از نحوه فراخوانی—PATH را در بالای اسکریپت، قبل از هر دستوری که به او وابسته است، صریح تعریف کنید:

#!/usr/bin/env bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
echo "Script PATH: $PATH"

به‌عنوان جایگزین، از مسیر مطلق کامل برای هر دستور استفاده کنید—مثلاً /usr/bin/python3 به‌جای python3—تا اسکریپت اصلاً به PATH وابسته نباشد.

گام ۲ — افزودن دایرکتوری به PATH برای نشست فعلی

استفاده از export برای تنظیم تغییر موقت PATH

دستور export، متغیری را برای به-ارث-رسیدن به پروسههای فرزند علامت‌گذاری کرده و فوراً در شل فعلی به‌روزرسانی‌اش می‌کند. برای افزودن دایرکتوری‌ای به PATH در نشست فعلی، برای اولویت بالاتر جلوی آن ببندید یا برای اولویت پایینتر، در انتهایش Append کنید:

# جلو ببندید: /opt/myapp/bin قبل از همه دایرکتوریهای موجود چک می‌شود
export PATH="/opt/myapp/bin:$PATH"

# Append کنید: /opt/myapp/bin بعد از همه دایرکتوریهای موجود چک می‌شود
export PATH="$PATH:/opt/myapp/bin"

جلوبندن به دایرکتوری جدید، اولویتِ بالاتری از دایرکتوریهای سیستمی می‌دهد—which وقتی نسخه جدیدتری از ابزاری را در کنار نسخه سیستمی نصب می‌کنید مفید است. Append کردن برای استفاده عمومی امن‌تر است.

تأیید اعمال شدن تغییر

دو دستور تغییر را تأیید می‌کنند: echo $PATH مقدار خام را نشان می‌دهد؛ و which نشان می‌دهد شل واقعاً کدام باینری را اجرا خواهد کرد:

echo $PATH
which myapp
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games:/opt/myapp/bin
/opt/myapp/bin/myapp

این تغییر فقط به نشست شل فعلی اعمال می‌شود. وقتی Terminal را ببندید یا نشست جدیدی شروع کنید، PATH به مقدار پیش‌فرضش Reset می‌شود.

گام ۳ — افزودن دایرکتوری به PATH به‌صورت دائم

انتخاب فایل پیکربندی درست

فایل راه‌اندازی درست به شل شما و اینکه نشست Login است یا تعاملیِ غیر-Login بستگی دارد. فایلی را انتخاب کنید که با نحوه راه‌اندازی شل‌تان مطابقت دارد.

فایلمحدودهکِی Source می‌شودشلها
~/.bashrcخاص-کاربرهر شل bashِ تعاملیِ غیر-Loginbash
~/.bash_profileخاص-کاربرشلهای Loginِ bash (معمولاً ~/.bashrc را Source می‌کند)bash
~/.profileخاص-کاربرشلهای Login وقتی ~/.bash_profile وجود نداردbash، sh، dash
~/.zshrcخاص-کاربرهر شل تعاملی zshzsh
~/.zprofileخاص-کاربرشلهای Loginِ zsh (معادل ~/.bash_profile برای zsh)zsh
/etc/environmentدر-سطح-سیستمتوسط PAM هنگام Login خوانده می‌شود؛ اسکریپت شل نیستهمه
/etc/profileدر-سطح-سیستمشلهای Loginbash، sh
/etc/profile.d/*.shدر-سطح-سیستمتوسط /etc/profile Source می‌شوندbash، sh

برای بیشتر استفادههای تعاملی روی دسکتاپ یا سروری که تنها کاربرش هستید، ~/.bashrc (یعنی bash) یا ~/.zshrc (یعنی zsh) فایل درست است.

ویرایش bashrc. برای کاربران Bash

Append کردن خط exportای به ~/.bashrc، تغییر PATH را در هر نشست bashِ تعاملی جدیدی در دسترس می‌سازد. فایل را باز کنید:

nano ~/.bashrc

به پایین اسکرول کرده و این را Append کنید:

export PATH="$PATH:/opt/myapp/bin"

تغییر را بدون Logout خارج شدن بارگذاری کنید:

source ~/.bashrc

تأیید کنید:

echo $PATH

اگر /opt/myapp/bin در خروجی ظاهر شد، به‌روزرسانی برای دستورات جدید در Terminal فعلی فعال است.

ویرایش zshrc. برای کاربران Zsh

برای zsh، فایل معادل ~/.zshrc است. بازش کنید:

nano ~/.zshrc

خط export را Append کنید:

export PATH="$PATH:/opt/myapp/bin"

پیکربندی را Reload کنید:

source ~/.zshrc

تأیید کنید:

echo $PATH

اگر سیستم‌تان شلهای Loginِ zsh باز می‌کند—not تعاملیِ غیر-Login—to‌جایش از ~/.zprofile استفاده کنید.

ویرایش /etc/environment برای تغییرات در-سطح-سیستم

/etc/environment توسط PAM هنگام Login پارس می‌شود و اسکریپت شل نیست؛ پس سینتکس شل—including بسط متغیر $PATH—در آن کار نمی‌کند. قبل از ویرایش، مقدار فعلی را بخوانید:

grep PATH /etc/environment

فایل را ویرایش کنید:

sudo nano /etc/environment

مقدار Literal کامل را—شامل دایرکتوریهای موجود و مورد جدید—تنظیم کنید:

PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/myapp/bin"

هشدار: از $PATH داخل /etc/environment استفاده نکنید. بسط متغیر در این فایل پشتیبانی نمی‌شود. همیشه فهرست کامل دایرکتوریها را به‌صورت رشته Literal بنویسید.

تغییرات /etc/environment بعد از Login بعدی اثر می‌کنند—not بعد از Source کردن در شل فعلی.

Reload کردن پیکربندی شل بدون Logout

خط export جدیدِ نوشته‌شده به ~/.bashrc تا وقتی فایل Source نشود فعال نیست. سه روش بدون نیاز به Logout پیکربندی را Reload می‌کنند:

# Source مستقیم فایل
source ~/.bashrc

# میان‌بر معادل
~/.bashrc .

# جایگزینی پروسه شل فعلی (bashrc~/. را Source می‌کند ولی نه ~/.bash_profile را)
exec bash

exec bash شل تعاملیِ غیر-Login جدیدی شروع می‌کند؛ پس ~/.bashrc را Source می‌کند—but نه ~/.bash_profile را. اگر خط export شما فقط در ~/.bash_profile است، source ~/.bash_profile را اجرا کنید یا نشست Login جدیدی باز کنید.

گام ۴ — تأیید کار کردن تغییرات PATH

استفاده از which برای چک Resolve شدن باینری

which اولین مورد اجراییِ منطبق با نام دستور را در سراسر دایرکتوریهای PATH برمی‌گرداند. بعد از تغییر PATH، اجرایش کنید تا تأیید کنید شل دستور را به باینری مورد انتظار Resolve می‌کند:

which python3
/usr/bin/python3

مسیر برگردانده‌شده همان چیزی است که شل دفعه بعد که دستور را اجرا می‌کنید اجرا خواهد کرد—with فرض اینکه چیزی در کش Hash مربوط به bash یا جدول Alias، Override‌اش نکند.

استفاده از type و command -v برای تأیید

type -a فراتر از which می‌رود. هر مورد منطبق در سراسر PATH—to‌همراه هر Alias یا تابع شلیِ هم‌نام—را گزارش می‌کند. وقتی استفاده‌اش کنید که لازم است تأیید کنید نسخه درست اول در ترتیب Resolution است:

type -a python3
python3 is /usr/bin/python3
python3 is /usr/local/bin/python3

برای چک تک-مسیرِ سازگار با POSIX، command -v را اجرا کنید:

command -v python3
/usr/bin/python3

type یک Builtin شل است که Aliasها، توابع و همه موارد PATH را گزارش می‌کند؛ در حالی که which فقط دایرکتوریهای PATH را چک کرده و اولین مورد را برمی‌گرداند. از type -a وقتی استفاده کنید که لازم است همه کاندیدها را برای تشخیص تعارض نسخه ببینید.

باز کردن نشست Shell جدید برای تأیید ماندگاری

اجرای echo $PATH در همان نشستی که export را اعمال کرد، ماندگاری را تأیید نمی‌کند—فقط وضعیت نشست فعلی را تأیید می‌کند. پروسه Shell تازه‌ای شروع کنید تا تأیید کنید مقدار از فایل راه‌اندازی می‌آید:

exec bash
echo $PATH

اگر دایرکتوری جدید در خروجی ظاهر شد، فایل راه‌اندازی درست پیکربندی شده. اگر نه، خط export مفقود، در فایل اشتباه، یا زیر Guardِ Return زودهنگام نشسته.

گام ۵ — حذف یا یکتاسازی Entryها از PATH

حذف دستی دایرکتوری مشخص

برای حذف /opt/myapp/bin از نشست فعلی:

PATH=$(echo "$PATH" | sed -e 's|/opt/myapp/bin:||g' -e 's|:/opt/myapp/bin||g')
export PATH

الگوی دونقطه-انتهایی، دایرکتوری را وقتی به‌دنبالش دونقطه آمده حذف می‌کند—which موقعیتهای شروع و وسط را پوشش می‌دهد. الگوی دونقطه-ابتدایی هم وقتی قبلش دونقطه آمده حذفش می‌کند—which موقعیتهای وسط و انتها را پوشش می‌دهد. اجرای هر دو با هم، همه موقعیتها را پوشش می‌دهد. بعد از آن echo $PATH را برای تأیید حذف اجرا کنید.

جلوگیری از Entryهای تکراری هنگام Source کردن فایلهای کانفیگ

Source کردن ~/.bashrc چند بار در نشستی—مثلاً بعد از ویرایش—می‌تواند هر بار همان دایرکتوری را Append کند. از این الگوی Guardای استفاده کنید تا مسیر فقط یک‌بار اضافه شود:

case ":$PATH:" in
  *":/opt/myapp/bin:"*) ;;
  *) export PATH="$PATH:/opt/myapp/bin" ;;
esac

پیچاندن دونقطه دور هر دو $PATH و دایرکتوری هدف، باعث می‌شود الگو با Entry کامل مطابقت یابد—not زیررشته‌ای از مسیر طولانی‌تر.

عیب‌یابی مسائل رایج PATH

تغییر PATH بعد از Logout ماندگار نمی‌شود

دستور export، PATH را فقط در پروسه شل فعلی به‌روزرسانی می‌کند. وقتی آن پروسه خارج شود، تغییر از بین می‌رود. برای تأیید همین اتفاق، Terminal جدیدی باز کرده و اجرا کنید:

echo $PATH

اگر دایرکتوریِ افزوده‌شده‌تان غایب است، تغییر هرگز به فایل راه‌اندازی نوشته نشده. برای ردیابی دقیق اینکه bash هنگام Login کدام فایلها را به چه ترتیبی Source می‌کند، این را اجرا کنید:

bash -lxv 2>&1 | head -50

فلگ -l شل Loginای را اجباری می‌کند، -x خروجی Trace را فعال کرده و -v هر خط را وقتی خوانده می‌شود چاپ می‌کند. به دنبال خطوطی بگردید که ~/.profile، ~/.bash_profile یا /etc/profile را Source می‌کنند تا تأیید کنید کدام فایل PATHِ Login شما را کنترل می‌کند. سپس خط export را به فایل درست Append کرده و Source کنید:

echo 'export PATH="$PATH:/opt/myapp/bin"' >> ~/.bashrc
source ~/.bashrc

Command Not Found بعد از افزودن به PATH

علت: PATH در Subshell یا اسکریپتی که خارج شده به‌روزرسانی شده، فایل راه‌اندازی اشتباه ویرایش شده، یا نشست فعلی هنوز تغییر را بارگذاری نکرده. تشخیص:

echo $PATH
grep -n PATH ~/.bashrc ~/.profile ~/.bash_profile 2>/dev/null

تأیید کنید که خط export در فایل درست موجود و source اجرا شده یا نشست جدیدی باز شده.

نسخه اشتباه باینری Resolve می‌شود

علت: دایرکتوری حاوی نسخه قدیمیترِ باینری، زودتر از دایرکتوری حاوی نسخه جدیدتر در PATH ظاهر می‌شود. تشخیص:

type -a python3

رفع: دایرکتوری حاوی نسخه موردنظر را با export PATH="/opt/myapp/bin:$PATH" جلو ببندید؛ یا دایرکتوری حاوی نسخه ناخواسته را با الگوی sed از گام ۵ حذف کنید.

تغییرات PATH روی اپلیکیشنهای GUI اعمال نمی‌شود

علت: بیشتر محیطهای دسکتاپ هنگام Login یعنی ~/.profile و /etc/environment را Source می‌کنند—not ~/.bashrc را. تغییری در ~/.bashrc فقط بر شبیه‌سازهای Terminal—which شلهای تعاملیِ غیر-Login تولید می‌کنند—اثر می‌گذارد. رفع: خط export را به ~/.profile منتقل کنید؛ یا دایرکتوری را به /etc/environment اضافه کرده؛ سپس Logout و دوباره Login کنید.

مدیریت PATH در محیطهای غیر-استاندارد

PATH در اسکریپتهای شل و Cron Jobها

Cron با PATH پیش‌فرضِ مینیمالی (معمولاً /usr/bin:/bin) اجرا می‌شود. دستوراتی که در شل تعاملی‌تان موجودند ممکن است پیدا نشوند. PATH را در بالای فایل crontab—قبل از هر تعریف Jobای—تنظیم کنید. Crontab را با crontab -e باز کرده و تخصیص PATH را اول اضافه کنید:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# اجرای myapp هر ساعت
0 * * * * /opt/myapp/bin/myapp >> /var/log/myapp.log 2>&1

خط PATH به هر Jobی که زیرش در همان فایل crontab تعریف شده اعمال می‌شود. اگر اسکریپتی که توسط cron صدا زده می‌شود هم به دستورات وابسته-به-PATH تکیه دارد، همان تخصیص PATH را در بالای آن اسکریپت اضافه کنید.

PATH در کانتینرهای داکر و Dockerfileها

از دستورالعمل ENV در Dockerfile برای گسترش PATHِ Image استفاده کنید:

ENV PATH="/opt/myapp/bin:${PATH}"

ENV در سراسر لایههای بعدی و درون کانتینرِ در-حال-اجرا ماندگار است؛ پس هر دستورالعمل RUN، CMD و ENTRYPOINT مقدار به-روزشده را می‌بیند.

استفاده از direnv برای مدیریت PATH خاص-پروژه

direnv متغیرهای محیطی را هنگام ورود یا خروج از دایرکتوری خودکار بارگذاری و Unload می‌کند. نصبش کنید و Hook شل را به فایل راه‌اندازی‌تان اضافه کنید:

sudo apt install direnv
echo 'eval "$(direnv hook bash)"' >> ~/.bashrc
source ~/.bashrc

روی راکی لینوکس، فدورا یا RHEL، خط نصب را با sudo dnf install direnv جایگزین کنید. برای کاربران zsh روی هر توزیعی، در دستور Hook به‌جای bash از zsh استفاده کنید. Hook الزامی است. بدون آن، direnv هنگام تغییر دایرکتوری فعال نمی‌شود.

فایل .envrc را در ریشه پروژه‌تان بسازید:

PATH_add ./bin

یک‌بار اجازه‌اش بدهید:

direnv allow

PATH وقتی cd از پروژه خارج می‌شوید به مقدار قبلی برمی‌گردد.

دامهای رایج PATH در پروداکشن

سناریوهای زیر رایج‌ترین دلایلی‌اند که PATHِ درست-پیکربندی‌شده همچنان در دیپلویهای واقعی طبق انتظار کار نمی‌کند.

sudo یعنی PATH شما را نادیده می‌گیرد

اجرای دستوری با sudo اغلب—even وقتی دستور بدون sudo کار می‌کند—with خطای «command not found» شکست می‌خورد. علت، secure_path در /etc/sudoers است—which هنگام فراخوانی sudo، PATH را کاملاً جایگزین می‌کند.

مقدار secure_path فعلی را چک کنید:

sudo grep secure_path /etc/sudoers
Defaults    secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

اگر /opt/myapp/bin فهرست نشده، sudo myapp فارغ از PATH کاربری شما شکست خواهد خورد. برای رفع بدون غیرفعال کردن secure_path، از مسیر کامل استفاده کنید:

sudo /opt/myapp/bin/myapp

یا دایرکتوری را با ویرایش /etc/sudoers با visudo به secure_path اضافه کنید:

sudo visudo

خط secure_path را تغییر بدهید تا دایرکتوری‌تان شامل شود:

Defaults    secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/myapp/bin"

هشدار: همیشه از visudo برای ویرایش /etc/sudoers استفاده کنید. ویرایش مستقیم فایل با ویرایشگر متنی و معرفی خطای سینتکسی، شما را از sudo روی آن سیستم بیرون می‌کِشد.

شلهای غیر-تعاملی SSH یعنی bashrc. را Source نمی‌کنند

اجرای دستوری روی SSH با ssh user@host 'mycommand' شل غیر-تعاملیِ غیر-Loginای می‌سازد. این شل نه ~/.bashrc و نه ~/.bash_profile را Source می‌کند؛ پس تغییرات PATH در آن فایلها برایش نامرئی‌اند.

برای تأیید اینکه شل غیر-تعاملی SSH چه PATHای می‌بیند:

ssh user@host 'echo $PATH'
/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin

خروجی، PATH سیستمیِ مینیمالی است که sshd تنظیم کرده—بدون هیچ‌کدام از دایرکتوریهای فایلهای راه‌اندازی شل تعاملی شما. برای در دسترس کردن PATH در این زمینه، در ~/.bashrc تنظیمش کنید و بلاک را Guard کنید تا حتی در شلهای غیر-تعاملی اجرا شود:

export PATH="$PATH:/opt/myapp/bin"

چک کنید آیا Guardای مثل [ -z "$PS1" ] && return نزدیک بالای ~/.bashrc شما وجود دارد. این خط باعث می‌شود bash برای شلهای غیر-تعاملی زودهنگام خارج شود—و همه چیزهای زیرش را رد کند. اگر Guard موجود است، خط export PATH را بالای آن منتقل کنید. اگر Guard غایب است، خط export می‌تواند در پایین فایل بماند. به‌عنوان جایگزین، PATH را در ~/.profile تعریف و مطمئن شوید ~/.bashrc آن را Source می‌کند.

bash مکان باینریها را Cache می‌کند

بعد از به‌روزرسانی PATH، bash ممکن است همچنان باینری قدیمی را اجرا کند—چون مکان دستوراتِ از-پیش-اجرا-شده را در جدول Hash کش می‌کند. Entry کش‌شده، Lookup مربوط به PATH را برای آن نام دستور Override می‌کند.

بعد از تغییر PATH، کش را پاک کنید:

hash -r

برای چک اینکه آیا دستور خاصی Cache شده و به کجا اشاره می‌کند:

hash python3
hits    command
   3    /usr/bin/python3

اگر مسیر کش‌شده کهنه است، hash -r همه Entryها را پاک کرده و Lookupِ تازه PATH را در فراخوانی بعدی اجباری می‌کند.

تقدم Resolve شدن دستور

PATH اولین جایی نیست که bash هنگام اجرای دستور نگاه می‌کند. ترتیب Resolution این است:

۱. Aliasها (تعریف‌شده با alias)
۲. توابع شل
۳. Builtinهای شل (cd، echo، type و غیره)
۴. مکانهای Hash-شده (کش باینری که بالا توصیف شد)
۵. اسکن دایرکتوریهای PATH

این دلیل اینکه type -a برای تشخیص رفتار غیرمنتظره مفیدتر از which است. اگر type python3 مقدار python3 is aliased to python برگرداند، Alias بر هر Entry مربوط به PATH تقدم دارد. برای رسیدن به باینری، Alias را حذف یا تغییر نام بدهید.

ترکیب PATH در macOS با لینوکس متفاوت است

روی macOS، سیستم هنگام Login یعنی /usr/libexec/path_helper را اجرا می‌کند تا PATH را از دو منبع بسازد: /etc/paths (یک دایرکتوری در هر خط) و فایلهای داخل /etc/paths.d/. این قبل از فایلهای راه‌اندازی شل اجرا می‌شود؛ پس دایرکتوریهای فهرست‌شده آنجا قبل از هر چیزی در ~/.zshrc یا ~/.bash_profile در PATH ظاهر می‌شوند.

برای افزودن دایرکتوری‌ای در-سطح-سیستم روی macOS، در /etc/paths.d/ فایلی بسازید:

sudo sh -c 'echo /opt/myapp/bin > /etc/paths.d/myapp'

فایل بعد از Login بعدی اثر می‌کند. برای تأیید:

cat /etc/paths
ls /etc/paths.d/

نکته: این بخش فقط به macOS اعمال می‌شود. روی سیستمهای لینوکسیِ پوشش‌داده‌شده در این tutorial، /etc/paths و path_helper وجود ندارند.

PATH در یونیت‌های سرویس systemd

هنگام اجرای اپلیکیشنها به‌عنوان سرویسهای systemd، PATH از محیط کاربری شما به ارث نمی‌رسد. systemd سرویسها را با محیط مینیمالی شروع می‌کند. دستورات نصب‌شده در /opt/myapp/bin یا مکانهای مشابه پیدا نخواهند شد—مگر اینکه PATH صریحاً در فایل Unit تنظیم شود.

PATH را در بلاک [Service] فایل Unit تنظیم کنید:

[Service]
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/myapp/bin"
ExecStart=/opt/myapp/bin/myapp

برای چند متغیر محیطی، از EnvironmentFile استفاده کنید:

[Service]
EnvironmentFile=/etc/myapp/environment
ExecStart=/opt/myapp/bin/myapp

که /etc/myapp/environment شامل:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/myapp/bin
MYAPP_ENV=production

بعد از ویرایش فایل Unit، دیمن را Reload و سرویس را ری‌استارت کنید:

sudo systemctl daemon-reload
sudo systemctl restart myapp

سوالات متداول

متغیر محیطی PATH در لینوکس چیست؟

PATH، فهرستی از مسیرهای دایرکتوری—جدا شده با دونقطه—است که شل هنگام تایپ دستور، از چپ به راست جستجو می‌کند. وقتی python3 را اجرا می‌کنید، شل هر دایرکتوری در PATH را چک می‌کند تا اجراییِ به‌نام python3 پیدا کند؛ سپس اجرایش می‌کند. بدون PATH، هر دستور لازم داشت مسیر مطلق کاملش تایپ شود.

چطور PATH فعلی‌ام را در لینوکس ببینم؟

echo $PATH یا printenv PATH را در هر Terminalای اجرا کنید تا مقدار فعلی نمایش یابد. هر دو دستور همان فهرست دایرکتوریهای جداشده-با-دونقطه را چاپ می‌کنند. برای دیدن یک-دایرکتوری-در-هر-خط، tr ':' '\n' <<< "$PATH" را اجرا کنید.

تفاوت تغییر موقت و دائم PATH در لینوکس چیست؟

اجرای export PATH="$PATH:/new/dir" در Terminal، تغییر را فقط به شل فعلی اعمال می‌کند. وقتی نشست تمام شود، PATH به مقدارِ تنظیم‌شده توسط فایلهای راه‌اندازی برمی‌گردد. برای ماندگاری، خط export را به ~/.bashrc (یعنی bash) یا ~/.zshrc (یعنی zsh) بنویسید و فایل را Source کنید.

کدام فایل را برای افزودن دائم دایرکتوری به PATH در لینوکس ویرایش کنم؟

برای نشستهای bashِ تعاملی روی سرور یا دسکتاپی که به‌عنوان کاربر منفردی Login می‌کنید، ~/.bashrc را ویرایش کنید. برای نشستهای شل Login از ~/.profile یا ~/.bash_profile استفاده کنید؛ و وقتی تغییر باید به همه کاربران سیستم اعمال شود از /etc/environment. جدول گام ۳، محدوده و رفتار Sourcing هر فایل را فهرست می‌کند.

چرا PATH بعد از اجرای export در Terminal به‌روز نمی‌شود؟

export در اسکریپت، شل والد را متأثر نمی‌کند—چون اسکریپت در Subshell اجرا می‌شود. تغییرات باید Source شوند (. script.sh یا source script.sh) تا به شل فعلی اعمال؛ یا به فایل راه‌اندازی نوشته و در نشست جدیدی بارگذاری شوند. echo $PATH را بلافاصله بعد از export اجرا کنید تا تأیید کنید تغییر در نشست فعلی قابل مشاهده است.

چطور دایرکتوری‌ای به PATH در zsh اضافه کنم؟

~/.zshrc را در ویرایشگر متنی باز کنید، export PATH="$PATH:/opt/myapp/bin" را در پایین اضافه، فایل را ذخیره و source ~/.zshrc را اجرا کنید. برای شلهای Loginِ zsh، به‌جای ~/.zshrc از ~/.zprofile استفاده کنید.

چطور بعد از به‌روزرسانی PATH چک کنم دستوری به کدام باینری Resolve می‌شود؟

which python3 را اجرا کنید تا اولین مورد در PATH را ببینید. type -a python3 را اجرا کنید تا هر مورد در سراسر دایرکتوریهای PATH فهرست شود—which وقتی چند نسخه نصب است مفید است. command -v python3 را برای جایگزینِ قابل-انتقال-به-POSIX یعنی which اجرا کنید.

چطور دایرکتوری‌ای را از PATH در لینوکس حذف کنم؟

برای حذف /opt/myapp/bin از نشست فعلی این را اجرا کنید:

PATH=$(echo "$PATH" | sed -e 's|/opt/myapp/bin:||g' -e 's|:/opt/myapp/bin||g')
export PATH

برای دائمی کردن حذف، خط exportای که دایرکتوری را از ~/.bashrc، ~/.zshrc یا هر فایل راه‌اندازیِ حاوی‌اش اضافه کرده بود حذف یا کامنت کنید؛ سپس فایل را Source کنید.

نتیجه‌گیری

این tutorial، چرخه کامل مدیریت PATH در لینوکس را مرور کرد: خواندن مقدار فعلی، تغییرات موقت و دائم در bash و zsh، انتخاب فایل راه‌اندازی درست برای نوع نشست، تأیید Resolve شدن باینری درست، حذف و یکتاسازی Entryها؛ و تشخیص خرابیهایی که در محیطهای پروداکشن—including پاک شدن PATH توسط sudo، شلهای غیر-تعاملی SSH، کشهای کهنه باینری و ایزوله شدن سرویس systemd—رخ می‌دهند.

حالا می‌توانید PATH را برای هر ابزارِ نصب‌شده-توسط-کاربر پیکربندی، فایل راه‌اندازی درست را برای شل و حالت Login خودتان انتخاب؛ و تشخیص بدهید چرا دستوری پیدا نمی‌شود یا به باینری اشتباه Resolve می‌شود.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

همچنین ببینید
بستن
دکمه بازگشت به بالا