رفتن به محتوا
LoopX

ویرایش فایل با nano و vim

توی این درس یاد می‌گیری روی سروری که محیط گرافیکی ندارد، فایل تنظیمات را ویرایش کنی. با 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 گیر کنی (که برای همه اتفاق می‌افتد) بدانی چطور خارج شوی.

nano مثل یک دفترچه‌ی ساده است: باز می‌کنی، می‌نویسی و فهرست کارهایی که می‌شود کرد (ذخیره، خروج، جستجو) پایین صفحه چاپ شده. vim مثل یک دستگاه تایپ حرفه‌ای است با پدال‌های متعدد: در ابتدا گیج‌کننده است (چون «حالت» دارد: یک حالت برای حرکت و دستور، یک حالت برای تایپ)، ولی وقتی عادت کردی، خیلی سریع‌تر می‌شود و روی هر سروری هست.

nano همیشه در حالت تایپ است و میانبرها پایین صفحه‌اند. vim سه حالت اصلی دارد و با Esc همیشه به Normal برمی‌گردی.

در این درس ویرایشگرها را داخل یک ترمینال مجازی (tmux) اجرا کرده‌ام و صفحه‌ی واقعی‌شان را در هر مرحله با tmux capture-pane گرفته‌ام؛ پس چیزی که می‌بینی همان چیزی است که روی ترمینال خودت می‌آید. دو تابع کمکی برای شروع و گرفتن صفحه:

Terminal window
mkdir -p ~/ed && cd ~/ed
run_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 “مثال ۱: کدام ویرایشگر روی این سیستم پیش‌فرض است؟”
Terminal window
echo "EDITOR=${EDITOR:-تنظیم نشده}"
command -v nano vim vi
readlink -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 hello.txt. صفحه این شکلی است:

Terminal window
cd ~/ed
export LANG=C.UTF-8
run_in_tmux nano hello.txt
screen
خروجی
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 همیشه در حالت تایپ است، مستقیم می‌نویسی. خط تازه بنویس و دوباره صفحه را ببین:

Terminal window
cd ~/ed
tmux send-keys -t ed "hello from nano" Enter "second line"
sleep 0.5
screen
خروجی
GNU nano 7.2 hello.txt *
hello from nano
second 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 اسم فایل را می‌پرسد:

Terminal window
cd ~/ed
tmux send-keys -t ed C-o
sleep 0.5
screen | tail -5
خروجی
File 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 جواب می‌دهی):

Terminal window
cd ~/ed
tmux send-keys -t ed Enter C-x
sleep 0.5
echo "--- محتوای فایل ذخیره‌شده:"
cat hello.txt
خروجی
--- محتوای فایل ذخیره‌شده:
hello from nano
second 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 یعنی…

برای باز کردن: vim demo.txt. اول فایلی با سه خط می‌سازیم و باز می‌کنیم:

Terminal window
cd ~/ed
printf 'line one\nline two\nline three\n' > demo.txt
run_in_tmux vim demo.txt
screen
خروجی
line one
line two
line three
~
~
~
~
~
~
~
~
"demo.txt" 3L, 29B 1,1 All

وقتی vim باز می‌شود در حالت Normal است: هر کلیدی که می‌زنی یک دستور است، نه تایپ متن! خط آخر (statusline) اسم فایل و تعداد خط/بایت و جای مکان‌نما (1,1 یعنی خط ۱ ستون ۱) را نشان می‌دهد. خطوط ~ یعنی «بعد از آخر فایل».

مهم‌ترین قاعده‌ی vim: Esc همیشه تو را به حالت Normal برمی‌گرداند. اگر نمی‌دانی در کدام حالتی، دو بار Esc بزن.

برای تایپ باید وارد Insert شوی: کلید i (insert قبل از مکان‌نما)، a (بعد)، o (خط جدید زیر خط فعلی). مثلاً G (برو به آخر فایل) و o و تایپ:

Terminal window
cd ~/ed
tmux send-keys -t ed G o "added with vim"
sleep 0.4
screen
خروجی
line one
line two
line three
added with vim
~
~
~
~
~
~
~
-- INSERT -- 4,15 All

پایین -- INSERT -- نشان می‌دهد در حالت تایپ هستی. حالا Esc را بزن تا برگردی به Normal:

Terminal window
cd ~/ed
tmux send-keys -t ed Escape
sleep 0.3
screen | tail -2
خروجی
~
4,14 All

-- INSERT -- رفت. (ستون ۱۴ چون مکان‌نما روی آخرین حرف است.)

مثال ۶: حالت Command، ذخیره و خروج

Section titled “مثال ۶: حالت Command، ذخیره و خروج”

از Normal با : وارد Command mode می‌شوی (یک خط در پایین صفحه). مهم‌ترین دستورها:

دستور کار
:w ذخیره (write)
:q خروج (اگر تغییر ذخیره‌نشده نباشد)
:wq یا ZZ ذخیره و خروج
:q! خروج بدون ذخیره (دور ریختن تغییرها)
:w نام ذخیره با نام دیگر
Terminal window
cd ~/ed
tmux send-keys -t ed ":" "wq" Enter
sleep 0.5
echo "--- محتوای فایل بعد از :wq:"
cat demo.txt
خروجی
--- محتوای فایل بعد از :wq:
line one
line two
line three
added with vim

خط جدید ذخیره شد. حالا ببین اگر بدون ذخیره بخواهی خارج شوی چه می‌شود:

Terminal window
cd ~/ed
run_in_tmux vim demo.txt
tmux send-keys -t ed G o "temporary change" Escape
sleep 0.3
tmux send-keys -t ed ":" "q" Enter
sleep 0.4
screen | tail -2
خروجی
E37: No write since last change (add ! to override)
Press ENTER or type command to continue

vim جلوی خروج را گرفت: E37: No write since last change (add ! to override). برای دور ریختن تغییرها :q! را می‌زنی:

Terminal window
cd ~/ed
tmux send-keys -t ed ":" "q!" Enter
sleep 0.5
echo "--- فایل بدون تغییر ماند:"
cat demo.txt
خروجی
--- فایل بدون تغییر ماند:
line one
line two
line three
added with vim

در حالت Normal، / جستجو را شروع می‌کند:

Terminal window
cd ~/ed
run_in_tmux vim demo.txt
tmux send-keys -t ed "/two" Enter
sleep 0.4
screen | 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) و یکی را کپی/چسباندن:

Terminal window
cd ~/ed
tmux send-keys -t ed Escape ":" "q!" Enter
sleep 0.3
printf 'one\ntwo\nthree\n' > nums.txt
run_in_tmux vim nums.txt
tmux send-keys -t ed j dd
sleep 0.3
screen | head -3
echo "--- yy (کپی خط فعلی) و p (چسباندن):"
tmux send-keys -t ed yy p
sleep 0.3
screen | head -4
echo "--- u (واگرد):"
tmux send-keys -t ed u
sleep 0.3
screen | head -3
tmux send-keys -t ed ":" "q!" Enter
sleep 0.3
خروجی
one
three
~
--- yy (کپی خط فعلی) و p (چسباندن):
one
three
three
~
--- u (واگرد):
one
three
~

بعد از dd خط two رفت؛ yy + p خط فعلی (three) را کپی و زیرش چسباند؛ u آخرین تغییر (چسباندن) را برگرداند. هر دستور را می‌توانی با عدد تکرار کنی: 3dd سه خط حذف می‌کند، 5j پنج خط پایین می‌رود.

جایگزینی با دستور Command: :s/قدیم/جدید/ (در خط فعلی، اولین مورد) یا :%s/قدیم/جدید/g (در همه‌ی فایل، همه‌ی موارد). چون این‌ها دستور ex هستند، می‌توانی بدون صفحه، به‌صورت اسکریپتی هم اجرایشان کنی (vim -es):

Terminal window
cd ~/ed
printf 'port 80\nserver port 80 enabled\nname=web\n' > conf.txt
echo "--- قبل:"; cat conf.txt
vim -es -u NONE conf.txt <<'LXEOF'
:%s/80/8080/g
:wq
LXEOF
echo "--- بعد از :%s/80/8080/g :"; cat conf.txt
خروجی
--- قبل:
port 80
server port 80 enabled
name=web
--- بعد از :%s/80/8080/g :
port 8080
server port 8080 enabled
name=web

هر 80 به 8080 تبدیل شد. در vim تعاملی همین را در حالت Normal با :%s/80/8080/g و Enter می‌نویسی؛ با c در آخر (/gc) برای هر مورد تأیید می‌گیرد.

مثال ۱۰: اشتباه رایج، تایپ دستور در حالت Insert

Section titled “مثال ۱۰: اشتباه رایج، تایپ دستور در حالت Insert”

اگر فراموش کنی از Insert خارج شوی و :wq بنویسی، vim آن را به‌عنوان متن می‌پذیرد:

Terminal window
cd ~/ed
run_in_tmux vim notes.txt
tmux send-keys -t ed i "hello" ":wq"
sleep 0.4
screen | head -3
echo "..."
screen | tail -1
tmux send-keys -t ed Escape ":" "q!" Enter
sleep 0.3
خروجی
hello:wq
~
~
...
-- INSERT -- 1,9 All

متن hello:wq در خود فایل نوشته شد و خبری از ذخیره نیست (پایین هنوز -- INSERT -- است). راه‌حل: Esc و بعد :wq. و اگر گیر کردی: Esc Esc سپس :q! (خروج بدون ذخیره).

مثال ۱۱: ویرایش فایل‌های سیستم، sudo

Section titled “مثال ۱۱: ویرایش فایل‌های سیستم، sudo”

فایل‌های /etc مال root هستند. با sudo باز کن، و قبل از ویرایش یک کپی بگیر:

Terminal window
sudo cp /etc/hostname /etc/hostname.bak
ls -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)؛ در درس‌های بعد.

Terminal window
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 همیشه لازم می‌ماند.

می‌خواهم… 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

مثال ۱۰ برعکسش را دیدی؛ و اگر در Normal چیزی تایپ کنی هر حرف یک دستور می‌شود و متن به‌هم می‌ریزد. راه‌حل: اول i؛ و برای خروج از هر شک: Esc.

۲) گیر کردن و ندانستن راه خروج

Section titled “۲) گیر کردن و ندانستن راه خروج”

برای خروج از vim: Esc و بعد :q! (بدون ذخیره) یا :wq (با ذخیره). برای nano: Ctrl+X.

۳) ویرایش فایل بدون دسترسی نوشتن

Section titled “۳) ویرایش فایل بدون دسترسی نوشتن”
Terminal window
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 معادلش را توصیف کن: چه کلیدهایی را به‌ترتیب می‌زنی تا یک خط بنویسی، ذخیره کنی و خارج شوی؟

دیدن جواب
Terminal window
echo "خط اول من" > note.txt
cat note.txt
خروجی
خط اول من

در nano: nano note.txt، تایپ «خط اول من»، Ctrl+O، Enter (تأیید نام)، Ctrl+X.

✎ تمرینمتوسط

تمرین اصلی: یک فایل را در vim باز کن، یک خط اضافه کن و ذخیره کن. فایل todo.txt با دو خط بساز، در vim باز کن (G برای آخر، o برای خط جدید)، خط «خرید نان» را اضافه کن، Esc و :wq بزن و محتوا را نشان بده.

دیدن جواب
Terminal window
mkdir -p ~/ed2 && cd ~/ed2
tmux -u kill-server 2>/dev/null
printf 'task one\ntask two\n' > todo.txt
tmux -u new-session -d -s ed2 -x 60 -y 8 "vim todo.txt"
sleep 1
tmux send-keys -t ed2 G o "buy bread" Escape ":" "wq" Enter
sleep 0.6
cat todo.txt
tmux -u kill-server 2>/dev/null
خروجی
task one
task two
buy bread

(برای نمایش بهتر از انگلیسی استفاده کردم؛ در ترمینال خودت هر متنی می‌نویسی.)

✎ تمرینسخت

با vim در حالت اسکریپتی (vim -es) فایل app.conf را طوری تغییر بده که debug=false به debug=true تبدیل شود و یک خط log_level=info به آخر فایل اضافه شود؛ پس از آن محتوا را نشان بده. (راهنما: دستور ex :$put ='متن' یا :$a… ساده‌ترین: :$put ='log_level=info'.)

دیدن جواب
Terminal window
printf 'name=web\ndebug=false\nport=80\n' > app.conf
vim -es -u NONE app.conf <<'LXEOF'
:%s/debug=false/debug=true/
:$put ='log_level=info'
:wq
LXEOF
cat app.conf
خروجی
name=web
debug=true
port=80
log_level=info

:$put ='...' متن را بعد از آخرین خط ($) می‌گذارد.

؟ آزمونک
  1. در vim برای شروع تایپ چه می‌کنی؟

  2. خروج از vim بدون ذخیره‌ی تغییرها؟

  3. اگر در vim گیر کرده‌ای و نمی‌دانی در چه حالتی هستی؟

  4. در nano علامت ^O یعنی…

  5. :%s/80/8080/g چه می‌کند؟

  6. قبل از ویرایش یک فایل تنظیمات مهم چه کار می‌کنی؟

  • روی سرور بدون محیط گرافیکی باید یک ویرایشگر ترمینالی بلد باشی: nano (ساده، میانبرها پایین صفحه) و vim (همه‌جا).
  • nano: بنویس، Ctrl+O Enter ذخیره، 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+Xnano: ذخیره و خروج
Ctrl+Wnano: جستجو
vim fileباز کردن با vim
i / Escvim: ورود به Insert / برگشت به Normal
:w :q :wq :q!vim: ذخیره، خروج، هر دو، خروج بدون ذخیره
/word n Nvim: جستجو و پرش بین نتایج
dd yy p uvim: حذف خط، کپی خط، چسباندن، واگرد
:%s/old/new/gvim: جایگزینی در کل فایل
sudo cp f f.bak && sudo nano fبکاپ و ویرایش فایل سیستمی