توی این درس یاد میگیری روی سروری که محیط گرافیکی ندارد، فایل تنظیمات را ویرایش کنی. با nano شروع میکنی که ساده است و میانبرهایش پایین صفحه نوشته شده (Ctrl+O ذخیره، Ctrl+X خروج)، بعد vim را یاد میگیری که روی هر سروری هست و حالتهای مختلف دارد: Normal (حرکت و دستور)، Insert (تایپ) و Command (دستورهایی مثل :w، :wq، :q!). جستجو با /word و جایگزینی هم میآید. برای اینکه ببینی ویرایشگرها چه شکلیاند، صفحهی واقعی nano و vim را (از یک ترمینال مجازی) در هر مرحله نشان میدهم.
مسئله: سرور محیط گرافیکی ندارد
Section titled “مسئله: سرور محیط گرافیکی ندارد”روی لپتاپ فایل را با یک ویرایشگر گرافیکی (مثل VS Code) باز میکنی. روی سرور فقط یک ترمینال داری و باید فایلی مثل /etc/ssh/sshd_config یا nginx.conf را عوض کنی. پس باید حداقل یک ویرایشگر داخل ترمینال بلد باشی. و مهمتر از آن: وقتی تصادفاً در vim گیر کنی (که برای همه اتفاق میافتد) بدانی چطور خارج شوی.
تشبیه: دو نوع دفتر
Section titled “تشبیه: دو نوع دفتر”nano مثل یک دفترچهی ساده است: باز میکنی، مینویسی و فهرست کارهایی که میشود کرد (ذخیره، خروج، جستجو) پایین صفحه چاپ شده. vim مثل یک دستگاه تایپ حرفهای است با پدالهای متعدد: در ابتدا گیجکننده است (چون «حالت» دارد: یک حالت برای حرکت و دستور، یک حالت برای تایپ)، ولی وقتی عادت کردی، خیلی سریعتر میشود و روی هر سروری هست.
مثالهای عملی
Section titled “مثالهای عملی”در این درس ویرایشگرها را داخل یک ترمینال مجازی (tmux) اجرا کردهام و صفحهی واقعیشان را در هر مرحله با tmux capture-pane گرفتهام؛ پس چیزی که میبینی همان چیزی است که روی ترمینال خودت میآید. دو تابع کمکی برای شروع و گرفتن صفحه:
mkdir -p ~/ed && cd ~/edrun_in_tmux() { tmux -u kill-server 2>/dev/null; tmux -u new-session -d -s ed -x 66 -y 12 "$@"; sleep 1; }screen() { tmux capture-pane -t ed -p | sed -e :a -e '/^[[:space:]]*$/{$d;N;ba' -e '}'; }echo "توابع کمکی آماده شد (run_in_tmux و screen)"توابع کمکی آماده شد (run_in_tmux و screen)(این تابعها فقط برای ساختن این درساند؛ تو فقط ترمینال را باز میکنی و ویرایشگر را میزنی.)
مثال ۱: کدام ویرایشگر روی این سیستم پیشفرض است؟
Section titled “مثال ۱: کدام ویرایشگر روی این سیستم پیشفرض است؟”echo "EDITOR=${EDITOR:-تنظیم نشده}"command -v nano vim vireadlink -f "$(command -v editor)"EDITOR=تنظیم نشده/usr/bin/nano/usr/bin/vim/usr/bin/vi/usr/bin/nanoدستور editor در Ubuntu به ویرایشگر پیشفرض اشاره میکند (معمولاً nano). برنامههایی مثل crontab -e و sudoedit از متغیر EDITOR یا همین پیشفرض استفاده میکنند. تغییرش: export EDITOR=vim یا sudo update-alternatives --config editor.
مثال ۲: nano، صفحهی اول
Section titled “مثال ۲: nano، صفحهی اول”برای باز کردن یا ساختن فایل: nano hello.txt. صفحه این شکلی است:
cd ~/edexport LANG=C.UTF-8run_in_tmux nano hello.txtscreen GNU nano 7.2 hello.txt
[ New File ]^G Help ^O Write Out ^W Where Is ^K Cut ^T Execute^X Exit ^R Read File ^\ Replace ^U Paste ^J Justifyبالا نام برنامه و فایل؛ وسط فضای تایپ؛ پایین نوار میانبرها. علامت ^ یعنی کلید Ctrl (مثلاً ^X یعنی Ctrl+X). M- یعنی کلید Alt (Meta). چون nano همیشه در حالت تایپ است، مستقیم مینویسی. خط تازه بنویس و دوباره صفحه را ببین:
cd ~/edtmux send-keys -t ed "hello from nano" Enter "second line"sleep 0.5screen GNU nano 7.2 hello.txt *hello from nanosecond line
^G Help ^O Write Out ^W Where Is ^K Cut ^T Execute^X Exit ^R Read File ^\ Replace ^U Paste ^J Justifyبالا کنار اسم فایل یک ستاره (*) آمده: یعنی ذخیره نشده. برای ذخیره Ctrl+O (Write Out) را میزنی و nano اسم فایل را میپرسد:
cd ~/edtmux send-keys -t ed C-osleep 0.5screen | tail -5File Name to Write: hello.txt^G Help M-D DOS Format M-A Append M-B Backup File^C Cancel M-M Mac Format M-P Prepend ^T Browseبا Enter اسم را تأیید میکنی. سپس با Ctrl+X خارج میشوی؛ (اگر ذخیره نشده باشد میپرسد «ذخیره شود؟» و با y/n جواب میدهی):
cd ~/edtmux send-keys -t ed Enter C-xsleep 0.5echo "--- محتوای فایل ذخیرهشده:"cat hello.txt--- محتوای فایل ذخیرهشده:hello from nanosecond lineمثال ۳: میانبرهای مهم nano
Section titled “مثال ۳: میانبرهای مهم nano”| میانبر | کار |
|---|---|
Ctrl+O |
ذخیره (Write Out) |
Ctrl+X |
خروج (با پرسش ذخیره اگر لازم باشد) |
Ctrl+W |
جستجو (Where is)؛ با Alt+W نتیجهی بعدی |
Ctrl+\ |
جایگزینی (Replace) |
Ctrl+K |
بریدن خط فعلی |
Ctrl+U |
چسباندن (آنچه بریدهای) |
Ctrl+_ |
رفتن به شمارهی خط |
Alt+U / Alt+E |
واگرد (undo) / تکرار (redo) |
Ctrl+G |
راهنما |
Ctrl+C |
نمایش شمارهی خط و ستون |
دو دستور هنگام اجرای nano مفید است: nano -l فایل (شمارهی خط) و nano +15 فایل (باز کردن مستقیم روی خط ۱۵).
در nano کلید ^X یعنی…
علامت ^ در نوار پایین یعنی کلید Ctrl.
مثال ۴: vim، حالت Normal
Section titled “مثال ۴: vim، حالت Normal”برای باز کردن: vim demo.txt. اول فایلی با سه خط میسازیم و باز میکنیم:
cd ~/edprintf 'line one\nline two\nline three\n' > demo.txtrun_in_tmux vim demo.txtscreenline oneline twoline three~~~~~~~~"demo.txt" 3L, 29B 1,1 Allوقتی vim باز میشود در حالت Normal است: هر کلیدی که میزنی یک دستور است، نه تایپ متن! خط آخر (statusline) اسم فایل و تعداد خط/بایت و جای مکاننما (1,1 یعنی خط ۱ ستون ۱) را نشان میدهد. خطوط ~ یعنی «بعد از آخر فایل».
مهمترین قاعدهی vim: Esc همیشه تو را به حالت Normal برمیگرداند. اگر نمیدانی در کدام حالتی، دو بار Esc بزن.
مثال ۵: حالت Insert، تایپ
Section titled “مثال ۵: حالت Insert، تایپ”برای تایپ باید وارد Insert شوی: کلید i (insert قبل از مکاننما)، a (بعد)، o (خط جدید زیر خط فعلی). مثلاً G (برو به آخر فایل) و o و تایپ:
cd ~/edtmux send-keys -t ed G o "added with vim"sleep 0.4screenline oneline twoline threeadded with vim~~~~~~~-- INSERT -- 4,15 Allپایین -- INSERT -- نشان میدهد در حالت تایپ هستی. حالا Esc را بزن تا برگردی به Normal:
cd ~/edtmux send-keys -t ed Escapesleep 0.3screen | tail -2~ 4,14 All-- INSERT -- رفت. (ستون ۱۴ چون مکاننما روی آخرین حرف است.)
مثال ۶: حالت Command، ذخیره و خروج
Section titled “مثال ۶: حالت Command، ذخیره و خروج”از Normal با : وارد Command mode میشوی (یک خط در پایین صفحه). مهمترین دستورها:
| دستور | کار |
|---|---|
:w |
ذخیره (write) |
:q |
خروج (اگر تغییر ذخیرهنشده نباشد) |
:wq یا ZZ |
ذخیره و خروج |
:q! |
خروج بدون ذخیره (دور ریختن تغییرها) |
:w نام |
ذخیره با نام دیگر |
cd ~/edtmux send-keys -t ed ":" "wq" Entersleep 0.5echo "--- محتوای فایل بعد از :wq:"cat demo.txt--- محتوای فایل بعد از :wq:line oneline twoline threeadded with vimخط جدید ذخیره شد. حالا ببین اگر بدون ذخیره بخواهی خارج شوی چه میشود:
cd ~/edrun_in_tmux vim demo.txttmux send-keys -t ed G o "temporary change" Escapesleep 0.3tmux send-keys -t ed ":" "q" Entersleep 0.4screen | tail -2E37: No write since last change (add ! to override)Press ENTER or type command to continuevim جلوی خروج را گرفت: E37: No write since last change (add ! to override). برای دور ریختن تغییرها :q! را میزنی:
cd ~/edtmux send-keys -t ed ":" "q!" Entersleep 0.5echo "--- فایل بدون تغییر ماند:"cat demo.txt--- فایل بدون تغییر ماند:line oneline twoline threeadded with vimمثال ۷: جستجو در vim، /word
Section titled “مثال ۷: جستجو در vim، /word”در حالت Normal، / جستجو را شروع میکند:
cd ~/edrun_in_tmux vim demo.txttmux send-keys -t ed "/two" Entersleep 0.4screen | tail -3~~/two 2,6 Allمکاننما روی two رفت (خط ۲). با n نتیجهی بعدی، N قبلی، و ?متن جستجو بهسمت بالا. اگر به آخر برسد از اول ادامه میدهد (search hit BOTTOM, continuing at TOP). جستجو به حروف کوچک و بزرگ حساس است؛ با :set ignorecase یا \c در جستجو بیحساسش کن.
مثال ۸: ویرایش در Normal، حذف، کپی و واگرد
Section titled “مثال ۸: ویرایش در Normal، حذف، کپی و واگرد”در حالت Normal هر کلید یک دستور است. چند مورد پرکاربرد:
| کلید | کار |
|---|---|
h j k l |
چپ، پایین، بالا، راست (یا کلیدهای جهتدار) |
w / b |
کلمهی بعد / قبل |
0 / $ |
اول / آخر خط |
gg / G |
اول / آخر فایل |
x |
حذف یک حرف |
dd |
حذف (برش) کل خط |
yy / p |
کپی خط / چسباندن زیر خط فعلی |
u / Ctrl+r |
واگرد / تکرار |
o / O |
خط جدید زیر / بالای خط فعلی و ورود به Insert |
A |
رفتن به آخر خط و Insert |
. |
تکرار آخرین تغییر |
آزمایش: خط دوم را حذف کن (dd پس از رفتن با j) و یکی را کپی/چسباندن:
cd ~/edtmux send-keys -t ed Escape ":" "q!" Entersleep 0.3printf 'one\ntwo\nthree\n' > nums.txtrun_in_tmux vim nums.txttmux send-keys -t ed j ddsleep 0.3screen | head -3echo "--- yy (کپی خط فعلی) و p (چسباندن):"tmux send-keys -t ed yy psleep 0.3screen | head -4echo "--- u (واگرد):"tmux send-keys -t ed usleep 0.3screen | head -3tmux send-keys -t ed ":" "q!" Entersleep 0.3onethree~--- yy (کپی خط فعلی) و p (چسباندن):onethreethree~--- u (واگرد):onethree~بعد از dd خط two رفت؛ yy + p خط فعلی (three) را کپی و زیرش چسباند؛ u آخرین تغییر (چسباندن) را برگرداند. هر دستور را میتوانی با عدد تکرار کنی: 3dd سه خط حذف میکند، 5j پنج خط پایین میرود.
مثال ۹: جایگزینی، :s
Section titled “مثال ۹: جایگزینی، :s”جایگزینی با دستور Command: :s/قدیم/جدید/ (در خط فعلی، اولین مورد) یا :%s/قدیم/جدید/g (در همهی فایل، همهی موارد). چون اینها دستور ex هستند، میتوانی بدون صفحه، بهصورت اسکریپتی هم اجرایشان کنی (vim -es):
cd ~/edprintf 'port 80\nserver port 80 enabled\nname=web\n' > conf.txtecho "--- قبل:"; cat conf.txtvim -es -u NONE conf.txt <<'LXEOF':%s/80/8080/g:wqLXEOFecho "--- بعد از :%s/80/8080/g :"; cat conf.txt--- قبل:port 80server port 80 enabledname=web--- بعد از :%s/80/8080/g :port 8080server port 8080 enabledname=webهر 80 به 8080 تبدیل شد. در vim تعاملی همین را در حالت Normal با :%s/80/8080/g و Enter مینویسی؛ با c در آخر (/gc) برای هر مورد تأیید میگیرد.
مثال ۱۰: اشتباه رایج، تایپ دستور در حالت Insert
Section titled “مثال ۱۰: اشتباه رایج، تایپ دستور در حالت Insert”اگر فراموش کنی از Insert خارج شوی و :wq بنویسی، vim آن را بهعنوان متن میپذیرد:
cd ~/edrun_in_tmux vim notes.txttmux send-keys -t ed i "hello" ":wq"sleep 0.4screen | head -3echo "..."screen | tail -1tmux send-keys -t ed Escape ":" "q!" Entersleep 0.3hello:wq~~...-- INSERT -- 1,9 Allمتن hello:wq در خود فایل نوشته شد و خبری از ذخیره نیست (پایین هنوز -- INSERT -- است). راهحل: Esc و بعد :wq. و اگر گیر کردی: Esc Esc سپس :q! (خروج بدون ذخیره).
مثال ۱۱: ویرایش فایلهای سیستم، sudo
Section titled “مثال ۱۱: ویرایش فایلهای سیستم، sudo”فایلهای /etc مال root هستند. با sudo باز کن، و قبل از ویرایش یک کپی بگیر:
sudo cp /etc/hostname /etc/hostname.bakls -l /etc/hostname /etc/hostname.bak | awk '{print $1, $3, $9}'echo "ویرایش واقعی: sudo nano /etc/hostname (یا sudoedit /etc/hostname)"sudo rm /etc/hostname.bak-rw-r--r-- root /etc/hostname-rw-r--r-- root /etc/hostname.bakویرایش واقعی: sudo nano /etc/hostname (یا sudoedit /etc/hostname)sudoedit (یا sudo -e) امنتر است: ویرایشگر را با کاربر عادی روی یک کپی اجرا میکند و بعد جایگزین میکند. بعد از ویرایش تنظیمات سرویسها، قبل از ریستارت درستی را بسنج (مثلاً nginx -t، sshd -t)؛ در درسهای بعد.
tmux -u kill-server 2>/dev/null; echo "ترمینال مجازی بسته شد"ترمینال مجازی بسته شدپشت پرده: چرا vim حالت دارد؟
Section titled “پشت پرده: چرا vim حالت دارد؟”vim از ویرایشگر vi (۱۹۷۶) میآید که برای ترمینالهایی بدون ماوس و بدون کلیدهای Ctrl/Alt پیچیده ساخته شد. ایده: بهجای فشردن چند کلید همزمان (Ctrl+…)، حالت را عوض کن تا هر حرف ساده یک دستور شود. در Normal هر حرف یک عمل است (dd حذف خط، w یک کلمه جلو)، و دستورها مثل «جمله»اند: عمل + حرکت (d حذف + w کلمه = dw، d3w، d$ تا آخر خط). همین ترکیبپذیری باعث میشود ویرایشهای بزرگ با چند کلید انجام شود.
برای فرق vi و vim: روی بسیاری سرورها vi در واقع یک نسخهی کمامکانات vim (vim-tiny) یا یک لینک است؛ اصول یکی است. nano از پروژهی GNU است و برای سادگی ساخته شد. هیچکدام بهتر مطلق نیستند: nano برای ویرایشهای کوتاه و vim برای کار زیاد.
دو ویرایشگر دیگر که شاید ببینی: emacs (قدرتمند، با میانبرهای Ctrl/Alt) و micro (مثل nano ولی مدرنتر). و ویرایش از راه دور با VS Code (Remote-SSH) روی لپتاپ هم رایج است، ولی دانستن nano/vim همیشه لازم میماند.
جدولهای مرجع
Section titled “جدولهای مرجع”| میخواهم… | nano | vim |
|---|---|---|
| باز کردن | nano file.txt |
vim file.txt |
| تایپ | همیشه فعال | i (و a، o) |
| ذخیره | Ctrl+O Enter |
:w |
| خروج | Ctrl+X |
:q |
| ذخیره و خروج | Ctrl+O Enter Ctrl+X |
:wq یا ZZ |
| خروج بدون ذخیره | Ctrl+X سپس n |
:q! |
| جستجو | Ctrl+W |
/متن |
| جایگزینی | Ctrl+\ |
:%s/قدیم/جدید/g |
| حذف خط | Ctrl+K |
dd |
| واگرد | Alt+U |
u |
| رفتن به خط N | Ctrl+_ |
:N یا NG |
| حالت vim | ورود | خروج |
|---|---|---|
| Normal | Esc |
— |
| Insert | i، a، o |
Esc |
| Command | : (از Normal) |
Enter یا Esc |
| Visual | v (از Normal) |
Esc |
اشتباهات رایج
Section titled “اشتباهات رایج”۱) تایپ در حالت Normal vim
Section titled “۱) تایپ در حالت Normal vim”مثال ۱۰ برعکسش را دیدی؛ و اگر در Normal چیزی تایپ کنی هر حرف یک دستور میشود و متن بههم میریزد. راهحل: اول i؛ و برای خروج از هر شک: Esc.
۲) گیر کردن و ندانستن راه خروج
Section titled “۲) گیر کردن و ندانستن راه خروج”برای خروج از vim: Esc و بعد :q! (بدون ذخیره) یا :wq (با ذخیره). برای nano: Ctrl+X.
۳) ویرایش فایل بدون دسترسی نوشتن
Section titled “۳) ویرایش فایل بدون دسترسی نوشتن”echo "تلاش برای نوشتن در یک فایل فقطخواندنی:"echo test >> /etc/hostnameتلاش برای نوشتن در یک فایل فقطخواندنی:bash: /etc/hostname: Permission deniedبا کاربر عادی نمیتوانی /etc/hostname را بنویسی (Permission denied)؛ ویرایشگر هم همین را میگوید. راهحل: sudo nano فایل یا sudoedit فایل.
۴) ویرایش فایل بدون بکاپ
Section titled “۴) ویرایش فایل بدون بکاپ”اگر تنظیم nginx یا sshd را خراب کنی و بکاپ نداری، برگشت سخت است. راهحل: sudo cp فایل فایل.bak قبل از ویرایش (درس قبل: cp file{,.bak}).
۵) مشکل زبان فارسی در ترمینال
Section titled “۵) مشکل زبان فارسی در ترمینال”نمایش متن راستبهچپ در ترمینالها محدود است (حروف جدا یا ترتیب وارونه). برای فایلهای تنظیمات و کد از انگلیسی استفاده کن و متن فارسی را در ویرایشگر مناسب (مثل VS Code) بنویس.
بدون باز کردن ویرایشگر، یک فایل note.txt با یک خط بنویس (با echo) و بعد با nano معادلش را توصیف کن: چه کلیدهایی را بهترتیب میزنی تا یک خط بنویسی، ذخیره کنی و خارج شوی؟
دیدن جواب
echo "خط اول من" > note.txtcat note.txtخط اول مندر nano: nano note.txt، تایپ «خط اول من»، Ctrl+O، Enter (تأیید نام)، Ctrl+X.
تمرین اصلی: یک فایل را در vim باز کن، یک خط اضافه کن و ذخیره کن. فایل todo.txt با دو خط بساز، در vim باز کن (G برای آخر، o برای خط جدید)، خط «خرید نان» را اضافه کن، Esc و :wq بزن و محتوا را نشان بده.
دیدن جواب
mkdir -p ~/ed2 && cd ~/ed2tmux -u kill-server 2>/dev/nullprintf 'task one\ntask two\n' > todo.txttmux -u new-session -d -s ed2 -x 60 -y 8 "vim todo.txt"sleep 1tmux send-keys -t ed2 G o "buy bread" Escape ":" "wq" Entersleep 0.6cat todo.txttmux -u kill-server 2>/dev/nulltask onetask twobuy bread(برای نمایش بهتر از انگلیسی استفاده کردم؛ در ترمینال خودت هر متنی مینویسی.)
با vim در حالت اسکریپتی (vim -es) فایل app.conf را طوری تغییر بده که debug=false به debug=true تبدیل شود و یک خط log_level=info به آخر فایل اضافه شود؛ پس از آن محتوا را نشان بده. (راهنما: دستور ex :$put ='متن' یا :$a… سادهترین: :$put ='log_level=info'.)
دیدن جواب
printf 'name=web\ndebug=false\nport=80\n' > app.confvim -es -u NONE app.conf <<'LXEOF':%s/debug=false/debug=true/:$put ='log_level=info':wqLXEOFcat app.confname=webdebug=trueport=80log_level=info:$put ='...' متن را بعد از آخرین خط ($) میگذارد.
آزمونک
Section titled “آزمونک”در vim برای شروع تایپ چه میکنی؟
vim در Normal شروع میشود و حروف دستورند.
خروج از vim بدون ذخیرهی تغییرها؟
:q! تغییرها را دور میریزد؛ :wq ذخیره و خروج.
اگر در vim گیر کردهای و نمیدانی در چه حالتی هستی؟
Esc همیشه به Normal برمیگرداند.
در nano علامت ^O یعنی…
^ یعنی Ctrl.
:%s/80/8080/g چه میکند؟
% یعنی همهی خطها و g یعنی همهی موارد هر خط.
قبل از ویرایش یک فایل تنظیمات مهم چه کار میکنی؟
تا اگر خراب شد برگردانی.
جمعبندی
Section titled “جمعبندی”- روی سرور بدون محیط گرافیکی باید یک ویرایشگر ترمینالی بلد باشی: nano (ساده، میانبرها پایین صفحه) و vim (همهجا).
- nano: بنویس،
Ctrl+OEnter ذخیره،Ctrl+Xخروج،Ctrl+Wجستجو،Ctrl+K/Ctrl+Uبرش و چسباندن. - vim سه حالت دارد: Normal (دستور)، Insert (
i/a/o، تایپ)، Command (:)؛Escهمیشه به Normal برمیگرداند. - ذخیره/خروج در vim:
:w،:q،:wq(یاZZ)،:q!(بدون ذخیره)؛ جستجو/wordوn؛ جایگزینی:%s/a/b/g. - فایلهای سیستمی با
sudo(یاsudoedit) و بعد از گرفتن بکاپ ویرایش شوند. - هر حرفی که در Normal میزنی دستور است؛ اگر تایپ نمیشود، احتمالاً در Insert نیستی.
| دستور | کاری که میکند |
|---|---|
nano file | باز کردن/ساختن فایل با nano |
Ctrl+O ، Enter ، Ctrl+X | nano: ذخیره و خروج |
Ctrl+W | nano: جستجو |
vim file | باز کردن با vim |
i / Esc | vim: ورود به Insert / برگشت به Normal |
:w :q :wq :q! | vim: ذخیره، خروج، هر دو، خروج بدون ذخیره |
/word n N | vim: جستجو و پرش بین نتایج |
dd yy p u | vim: حذف خط، کپی خط، چسباندن، واگرد |
:%s/old/new/g | vim: جایگزینی در کل فایل |
sudo cp f f.bak && sudo nano f | بکاپ و ویرایش فایل سیستمی |