توی این درس یاد میگیری وقتی چیزی را در ترمینال تایپ میکنی دقیقاً چه کسی آن را میخواند و اجرا میکند: ترمینال (پنجره) و shell (مفسر دستورها) دو چیز جدا هستند. bash و zsh را میشناسی، ساختار یک دستور را (command، option، argument) میخوانی، میفهمی quote ها (' و ") برای چهاند، از تاریخچه و Tab برای سریعتر شدن استفاده میکنی و میانبرهای حیاتی Ctrl+C، Ctrl+R و Ctrl+L را یاد میگیری. دستورها: echo، whoami، history و clear.
مسئله: صفحهی سیاه و یک خط چشمکزن
Section titled “مسئله: صفحهی سیاه و یک خط چشمکزن”اولین بار که ترمینال را باز میکنی فقط یک خط چشمکزن میبینی و هیچ دکمهای نیست. هر چیزی را که تایپ کنی، یک «چیزی» میخواند و کاری میکند. آن «چیز» کیست؟ اگر ندانی، خطاهایی مثل command not found یا رفتار عجیب فاصلهها و quote ها گیجت میکند. این درس نقشهی کار را میدهد.
تشبیه: گیشه و کارمند
Section titled “تشبیه: گیشه و کارمند”ترمینال مثل گیشهی بانک است: پنجرهای که با آن حرف میزنی و جواب میبینی. shell مثل کارمندی است که پشت گیشه نشسته: حرف تو را میفهمد، به کارهای واقعی (برنامهها) تقسیم میکند و نتیجه را برمیگرداند. گیشه را میشود عوض کرد (چند برنامهی ترمینال مختلف) بدون اینکه کارمند عوض شود، و برعکس.
مثالهای عملی
Section titled “مثالهای عملی”مثال ۱: اولین دستور، echo
Section titled “مثال ۱: اولین دستور، echo”echo هر چه به آن بدهی را چاپ میکند. سادهترین دستور برای فهمیدن ساختار:
echo helloecho "سلام دنیا"echo یک دو سهhelloسلام دنیایک دو سهدستور اول echo است (command) و hello یک argument. در سومی سه argument داریم؛ ولی خروجی آنها را با یک فاصله چاپ کرد. بعد میبینی فاصلهها چه نقشی دارند.
مثال ۲: ساختار دستور، command و option و argument
Section titled “مثال ۲: ساختار دستور، command و option و argument”هر دستور سه نوع بخش دارد: command (چه کاری)، option (چطور؛ با - یا --) و argument (روی چه چیزی). با ls که فهرست فایلها را میدهد:
ls /etc/os-releasels -l /etc/os-releasels --long /etc/os-release 2>&1 | head -1ls -l -h /etc/os-releasels -lh /etc/os-release/etc/os-releaselrwxrwxrwx 1 root root 21 Sep 6 14:29 /etc/os-release -> ../usr/lib/os-releasels: unrecognized option '--long'lrwxrwxrwx 1 root root 21 Sep 6 14:29 /etc/os-release -> ../usr/lib/os-releaselrwxrwxrwx 1 root root 21 Sep 6 14:29 /etc/os-release -> ../usr/lib/os-releasels /etc/os-release: command + یک argument (فایل).-lیک option کوتاه (یک حرف) برای «فرمت بلند»؛ls --longوجود ندارد (option بلند باید--و اسم کامل باشد و هر دستور اسمهای خودش را دارد).- گزینههای کوتاه را میشود چسباند:
-l -hهمان-lhاست.
| بخش | مثال | معنی |
|---|---|---|
| command | ls |
کدام برنامه اجرا شود |
| option کوتاه | -l، -h |
رفتار برنامه را عوض میکند (حرف تکی، بعد از -) |
| option بلند | --help، --all |
همان با اسم کامل (بعد از --) |
| argument | /etc/os-release |
داده/فایلی که برنامه رویش کار میکند |
مثال ۳: ترمینال و shell، کدام است؟
Section titled “مثال ۳: ترمینال و shell، کدام است؟”شل فعلی را بپرس:
echo "نام shell من: $SHELL"echo "پروسهی فعلی: $(ps -p $$ -o comm=)"echo "نسخه: $(bash --version | head -1)"نام shell من: /bin/bashپروسهی فعلی: bashنسخه: GNU bash, version 5.2.21(1)-release (aarch64-unknown-linux-gnu)$SHELL شل پیشفرض کاربر است و $$ شمارهی پروسهی همین shell. فهرست shell های معتبر سیستم هم در یک فایل است:
cat /etc/shells# /etc/shells: valid login shells/bin/sh/usr/bin/sh/bin/bash/usr/bin/bash/bin/rbash/usr/bin/rbash/usr/bin/dash/bin/zsh/usr/bin/zsh/usr/bin/zshbash (Bourne Again SHell) پیشفرض اکثر توزیعها (از جمله Ubuntu) است و این دوره روی آن نوشته شده. zsh (روی مکهای جدید پیشفرض است) شبیه bash است با امکانات بیشتر در تکمیل و شخصیسازی. هر دو را میتوان روی یک سیستم داشت:
bash -c 'echo "bash اجرا کرد؛ نسخه $BASH_VERSION"'zsh -c 'echo "zsh اجرا کرد؛ نسخه $ZSH_VERSION"'bash اجرا کرد؛ نسخه 5.2.21(1)-releasezsh اجرا کرد؛ نسخه 5.9دستورهای ساده (ls، cd، echo) در هر دو یکساناند؛ تفاوتها در اسکریپتنویسی و شخصیسازی دیده میشود. (sh و dash هم shell های سادهترند که برای اسکریپتهای سیستمی به کار میروند.)
ترمینال و shell چه فرقی دارند؟
میشود ترمینال را عوض کرد بدون اینکه shell عوض شود.
مثال ۴: فاصله، quote و خرد کردن توسط shell
Section titled “مثال ۴: فاصله، quote و خرد کردن توسط shell”shell دستور را با فاصله خرد میکند. برای اینکه فاصله جزو یک argument باشد، باید quote بگذاری:
mkdir -p t && cd ttouch "my file.txt"lsecho "--- بدون quote (دو argument):"ls my file.txt 2>&1echo "--- با quote (یک argument):"ls "my file.txt"my file.txt--- بدون quote (دو argument):ls: cannot access 'my': No such file or directoryls: cannot access 'file.txt': No such file or directory--- با quote (یک argument):my file.txtبدون quote، shell my و file.txt را دو فایل جدا دید و خطا داد. نکتهی مهم: خطا از ls است، ولی علتش از تجزیهی shell. فرق دو نوع quote:
name="علی"echo "سلام $name"echo 'سلام $name'echo "امروز: $(date +%Y)"echo 'امروز: $(date +%Y)'سلام علیسلام $nameامروز: 2026امروز: $(date +%Y)داخل "..." (دابل) متغیر ($name) و $(...) جایگزین میشوند؛ داخل '...' (سینگل) همهچیز عیناً میماند. قاعدهی عملی: پیشفرض "..."؛ '...' وقتی نمیخواهی هیچچیز تفسیر شود.
مثال ۵: چه کسی هستم؟ whoami
Section titled “مثال ۵: چه کسی هستم؟ whoami”whoamiid -unecho $USERalialiهر سه نام کاربر فعلی را میدهند (دو تا اول دستورند، سومی یک متغیر محیطی). whoami در اسکریپتها و وقتی با sudo کار میکنی (sudo whoami را در درس root ببین) مهم است.
مثال ۶: تاریخچه، history
Section titled “مثال ۶: تاریخچه، history”shell دستورهای قبلی را نگه میدارد. در یک ترمینال تعاملی، فقط history را میزنی. اینجا (که اسکریپتی اجرا میشود) چند دستور را دستی به تاریخچه میدهیم تا خروجیاش را ببینی:
HISTFILE=/dev/null; set -o historyhistory -chistory -s "ls -l /etc"history -s "cd /var/log"history -s "echo سلام"history 1 ls -l /etc 2 cd /var/log 3 echo سلام 4 historyهر دستور یک شماره دارد. در ترمینال تعاملی از آن استفاده میکنی: !! (دستور قبلی را دوباره اجرا کن)، !42 (دستور شمارهی ۴۲)، !ls (آخرین دستوری که با ls شروع شد)، و مهمتر از همه Ctrl+R: جستجوی معکوس (مثال ۸). اندازهی تاریخچه در تنظیمات bash است:
grep -E '^HIST(SIZE|FILESIZE|CONTROL)' ~/.bashrcHISTCONTROL=ignorebothHISTSIZE=1000HISTFILESIZE=2000HISTSIZE تعداد دستورهای حافظه، HISTFILESIZE تعداد در فایل ~/.bash_history و HISTCONTROL=ignoreboth یعنی دستورهایی که با فاصله شروع میشوند یا تکراریاند ثبت نشوند. هشدار: رمزها را روی خط فرمان ننویس؛ تاریخچه آنها را در فایل ذخیره میکند.
مثال ۷: تکمیل با Tab
Section titled “مثال ۷: تکمیل با Tab”کلید Tab نام دستور و فایل را کامل میکند؛ اگر چند گزینه باشد، با دو بار Tab فهرست را نشان میدهد. چیزی که پشت Tab کار میکند را میتوانیم مستقیم ببینیم، دستور compgen:
echo "دستورهایی که با lsb شروع میشوند:"compgen -c lsb | sort -uecho "--- فایلهای /etc که با host شروع میشوند:"compgen -f /etc/hostدستورهایی که با lsb شروع میشوند:lsb_releaselsblk--- فایلهای /etc که با host شروع میشوند:/etc/hostname/etc/hosts/etc/host.conf/etc/hosts.allow/etc/hosts.denyاگر lsb و Tab بزنی، shell همین فهرست را میداند و تا جایی که یکتا است کامل میکند. استفادهی درست از Tab سرعت را چند برابر میکند و غلط تایپی را از بین میبرد؛ هر وقت اسمی طولانی دیدی، Tab بزن.
مثال ۸: میانبرها و clear
Section titled “مثال ۸: میانبرها و clear”میانبرهای صفحهکلید که روزی صد بار میزنی (در ترمینال تعاملی):
| میانبر | کار |
|---|---|
Ctrl+C |
قطع کردن دستور در حال اجرا (سیگنال SIGINT) |
Ctrl+D |
پایان ورودی؛ در خط خالی ترمینال را میبندد (exit) |
Ctrl+L |
پاک کردن صفحه (مثل clear) |
Ctrl+R |
جستجو در تاریخچه (بنویس و Enter بزن؛ دوباره Ctrl+R برای قبلی) |
Ctrl+A / Ctrl+E |
رفتن به اول / آخر خط |
Ctrl+U / Ctrl+K |
پاک کردن تا اول / تا آخر خط |
Ctrl+W |
پاک کردن کلمهی قبل از مکاننما |
Ctrl+Z |
متوقف کردن موقت دستور (درس پروسهها) |
↑ / ↓ |
دستورهای قبلی/بعدی |
Ctrl+C همان سیگنال INT است. میتوانیم اثرش را ببینیم: timeout دستوری را با سیگنال انتخابی قطع میکند:
timeout -s INT 1 sleep 10echo "کد خروج: $?"کد خروج: 124دستور sleep 10 بعد از ۱ ثانیه با سیگنال INT قطع شد و کد خروج 124 (کدی که timeout برای «قطع شد» برمیگرداند) آمد. و clear چه میکند؟ فقط یک رشتهی کنترلی برای ترمینال میفرستد:
TERM=xterm clear | od -c | head -20000000 033 [ H 033 [ 2 J 033 [ 3 J0000013033 [ H 033 [ 2 J یعنی «مکاننما را به بالا ببر و صفحه را پاک کن». پس clear برنامهای است که به ترمینال دستور میدهد، نه کاری روی فایلها.
مثال ۹: کد خروج، دستور موفق شد یا نه؟
Section titled “مثال ۹: کد خروج، دستور موفق شد یا نه؟”هر دستور بعد از اجرا یک عدد برمیگرداند: ۰ یعنی موفق، غیر صفر یعنی خطا. shell آن را در $? نگه میدارد:
true; echo "true → $?"false; echo "false → $?"ls /etc/os-release > /dev/null; echo "ls فایل موجود → $?"ls /nonexistent 2>/dev/null; echo "ls فایل ناموجود → $?"true → 0false → 1ls فایل موجود → 0ls فایل ناموجود → 2این عدد در اسکریپتها و ترکیب دستورها (&& و || در درسهای بعد) اساس تصمیمگیری است.
پشت پرده: shell چه میکند؟
Section titled “پشت پرده: shell چه میکند؟”وقتی ls -l /etc را مینویسی و Enter میزنی، shell این مراحل را میرود: ۱) خرد کردن خط با فاصله به کلمهها (و قانون quote)؛ ۲) جایگزینیها: متغیرها ($name)، $(...)، و wildcard ها (*)؛ ۳) پیدا کردن دستور: اول builtin های خود shell (مثل cd، echo)، بعد برنامهای با آن نام در پوشههای $PATH؛ ۴) fork: یک کپی از shell ساخته میشود؛ ۵) کپی با exec برنامهی ls را جایگزین خودش میکند؛ ۶) shell منتظر میماند تا تمام شود و کد خروج را در $? ذخیره میکند.
همین است که cd باید builtin باشد: اگر برنامهی جدا بود، فقط پوشهی کپی را عوض میکرد نه shell اصلی را. و همین است که فاصله و quote اهمیت دارند: تجزیه قبل از اجرای برنامه انجام میشود، پس خود برنامه (مثل ls) فقط argument های آماده میگیرد.
جدولهای مرجع
Section titled “جدولهای مرجع”| دستور | کار | مثال |
|---|---|---|
echo متن |
چاپ متن | echo "سلام" |
echo -n |
بدون خط جدید | echo -n "بدون newline" |
whoami |
نام کاربر فعلی | whoami |
history |
فهرست دستورهای قبلی | history | tail -5 |
clear |
پاک کردن صفحه | clear یا Ctrl+L |
echo $? |
کد خروج دستور قبلی | ls /x; echo $? |
compgen -c prefix |
دستورهایی که با پیشوند شروع میشوند | compgen -c lsb |
| نوع quote | متغیر و $(...) |
کاربرد |
|---|---|---|
"..." |
جایگزین میشوند | پیشفرض، وقتی فاصله هست |
'...' |
عیناً میماند | وقتی نمیخواهی چیزی تفسیر شود |
| بدون quote | جایگزین و خرد میشوند | فقط وقتی مطمئنی فاصله/علامت خاص نیست |
اشتباهات رایج
Section titled “اشتباهات رایج”۱) فاصله در اسم فایل بدون quote
Section titled “۱) فاصله در اسم فایل بدون quote”مثال ۴: ls my file.txt دو فایل میبیند. راهحل: quote، یا \ (بکاسلش) قبل از فاصله: ls my\ file.txt.
۲) دستور نوشتهشده با حروف اشتباه
Section titled “۲) دستور نوشتهشده با حروف اشتباه”lss -lbash: lss: command not foundاسم دستور اشتباه است و shell چنین برنامهای پیدا نمیکند: command not found. راهحل: با Tab کامل کن؛ بین ls و l فرق هست و حروف کوچک/بزرگ مهماند (LS هم پیدا نمیشود).
۳) فاصله دور علامت = در تعریف متغیر
Section titled “۳) فاصله دور علامت = در تعریف متغیر”name = "علی"bash: name: command not foundدر shell نباید دور = فاصله باشد. با فاصله، name بهعنوان یک دستور اجرا میشود. راهحل: name="علی".
۴) گیر کردن در یک دستور که تمام نمیشود
Section titled “۴) گیر کردن در یک دستور که تمام نمیشود”بعضی دستورها (مثل cat بدون فایل یا sleep 1000) تمام نمیشوند و مکاننما برنمیگردد. راهحل: Ctrl+C. (برای cat بدون فایل، Ctrl+D هم پایان ورودی میدهد.)
۵) paste کردن دستورهایی که نمیفهمی
Section titled “۵) paste کردن دستورهایی که نمیفهمی”echo 'rm -rf /' | catrm -rf /دستورهای خطرناک را از اینترنت مستقیم paste نکن؛ بالا فقط آن را «چاپ» کردیم، ولی اگر اجرا میشد میتوانست همهچیز را پاک کند. راهحل: اول echo یا man بزن و بفهم هر بخش چه میکند.
دستور echo را سه بار با سه argument مختلف اجرا کن؛ بعد با whoami نام کاربرت را بگو و با echo $? ببین whoami موفق بوده یا نه.
دیدن جواب
echo یکecho "دو و سه"echo 'چهار $HOME'whoamiecho "کد خروج whoami: $?"یکدو و سهچهار $HOMEaliکد خروج whoami: 0تمرین اصلی: با Ctrl+R یک دستور قدیمی را پیدا و دوباره اجرا کن. چون اینجا ترمینال تعاملی نیست، همان مفهوم را با تاریخچهی ساختگی انجام بده: سه دستور به history بده، با history | grep یکی را پیدا کن و شمارهاش را بگیر. (در ترمینال واقعی: Ctrl+R بزن، چند حرف از دستور را بنویس، Enter.)
دیدن جواب
HISTFILE=/dev/null; set -o history; history -chistory -s "ls -l /etc"history -s "cd /var/log"history -s "echo پروژهی من"history | grep "var/log" 2 cd /var/log 4 history | grep "var/log"در ترمینال واقعی با Ctrl+R و نوشتن var/log همین دستور را مییابی و با Enter دوباره اجرا میکنی؛ یا شمارهاش را با !2 صدا میزنی.
یک فایل به اسم my report 2026.txt (با فاصله) بساز، سه روش مختلف برای اشاره به آن در ls بنویس (دابلquote، سینگلquote، بکاسلش) و نشان بده روش بدون quote خطا میدهد.
دیدن جواب
touch "my report 2026.txt"ls "my report 2026.txt"ls 'my report 2026.txt'ls my\ report\ 2026.txtecho "--- بدون quote:"ls my report 2026.txt 2>&1 | head -3my report 2026.txtmy report 2026.txtmy report 2026.txt--- بدون quote:ls: cannot access 'my': No such file or directoryls: cannot access 'report': No such file or directoryls: cannot access '2026.txt': No such file or directoryآزمونک
Section titled “آزمونک”کدام یک پنجرهی ورودی/خروجی است و کدام مفسر دستورها؟
bash و zsh نمونههای shellاند.
در ls -lh /etc، کدام بخش argument است؟
ls command است، -lh option و /etc argument.
تفاوت echo "$HOME" و echo '$HOME'؟
پیشفرض دابلquote.
کد خروج ۰ یعنی…
غیر صفر خطا است؛ مقدارش به نوع خطا بستگی دارد.
Ctrl+R برای چیست؟
Ctrl+C قطع، Ctrl+L پاک کردن.
چرا cd باید builtin باشد؟
برنامهی جدا فقط پوشهی خودش را عوض میکرد.
جمعبندی
Section titled “جمعبندی”- ترمینال پنجره است؛ shell (مثل bash) دستور را میخواند، تجزیه و اجرا میکند. zsh شبیه bash با امکانات بیشتر است.
- هر دستور: command + optionها (
-l،--help) + argumentها. shell با فاصله خرد میکند؛ برای فاصله در اسم، quote بگذار. "..."متغیر و$(...)را جایگزین میکند؛'...'عیناً نگه میدارد.- کد خروج در
$?: ۰ موفق، غیر صفر خطا. - تاریخچه (
history،!!،Ctrl+R) و Tab سرعت و دقت را بالا میبرند؛ رمز را روی خط فرمان نگذار. - میانبرها:
Ctrl+Cقطع،Ctrl+Dپایان ورودی،Ctrl+Lپاک کردن صفحه،Ctrl+A/Eاول/آخر خط.
| دستور | کاری که میکند |
|---|---|
echo "متن" | چاپ متن |
whoami | نام کاربر فعلی |
history | فهرست دستورهای قبلی |
clear (یا Ctrl+L) | پاک کردن صفحه |
echo $? | کد خروج دستور قبلی |
echo $SHELL | shell پیشفرض |
cat /etc/shells | shell های معتبر سیستم |
Ctrl+C / Ctrl+D | قطع دستور / پایان ورودی |
Ctrl+R | جستجو در تاریخچه |
compgen -c prefix | دستورهایی که با پیشوند شروع میشوند |