دسته بندی:

دستورات کاربردی لینوکس: راهنمای خط فرمان برای مدیران سرور

پشت یک اتصال SSH نشسته‌اید، هیچ محیط گرافیکی‌ای در کار نیست و باید یک فایل را روی سرور دانلود کنید، از حالت فشرده خارجش کنید، جابه‌جایش کنید و آخر کار لاگ را بخوانید. همه‌ی این کارها با چند دستور کوتاه انجام می‌شود؛ مشکل اینجاست که یک اشتباه تایپی در همین چند دستور — مثلاً یک rm در مسیر اشتباه — روی سرور قابل بازگشت نیست. این راهنما دستورات کاربردی لینوکس را به همان ترتیبی می‌آورد که واقعاً موقع کار با سرور به آن‌ها می‌رسید، همراه با هشدارهای هر کدام.

قبل از هر چیز: اتصال به سرور و معنی # در نمونه‌کدها

برای اجرای این دستورها اول باید به شل سرور وصل شوید؛ با نرم‌افزار PuTTY یا هر کلاینت SSH دیگری. روی ویندوز ۱۰ به بعد، macOS و لینوکس دستور ssh به‌صورت داخلی موجود است و لازم نیست چیزی نصب کنید:

ssh root@XXX.XXX.XXX.XXX -p 22

نکته‌ای که در مستندهای قدیمی زیاد باعث سردرگمی می‌شود: نمونه‌کدها را اغلب این‌طور می‌نویسند:

# cat file.txt

آن # ابتدای خط بخشی از دستور نیست؛ فقط نشان می‌دهد پرامپت متعلق به کاربر root است (کاربر عادی به‌جایش $ می‌بیند). اگر آن را هم تایپ کنید، کل خط تبدیل به یک کامنت می‌شود و اصلاً اجرا نمی‌شود. در ادامه‌ی این مقاله دستورها بدون آن علامت نوشته شده‌اند.

حرکت در فایل‌سیستم: ls، cd و pwd

برای دیدن فایل‌ها و پوشه‌های مسیر فعلی:

ls -al

سوئیچ -a فایل‌های مخفی (آن‌هایی که نامشان با نقطه شروع می‌شود، مثل .htaccess) را هم نشان می‌دهد و -l خروجی را به شکل جدولی با دسترسی، مالک، حجم و تاریخ در می‌آورد. اگر حجم‌ها را خوانا می‌خواهید، -h را هم اضافه کنید:

ls -alh /var/www/html

برای رفتن به یک مسیر مشخص:

cd /home/directory/test

سه میان‌بُر که مدام به کارتان می‌آید: cd .. یک پوشه به عقب می‌رود، cd ~ شما را به پوشه‌ی خانگی می‌برد و cd - به آخرین مسیری که در آن بودید برمی‌گردد. اگر گم شدید، pwd مسیر فعلی را چاپ می‌کند. عادت خوب این است که قبل از هر دستور حذف یا انتقال، یک بار pwd بزنید.

موقع تایپ مسیرها هم چند حرف اول را بزنید و کلید Tab را فشار دهید؛ شل بقیه‌اش را کامل می‌کند. این کار هم سریع‌تر است و هم جلوی غلط تایپی در مسیر را می‌گیرد.

ساخت، کپی، انتقال و حذف فایل و پوشه

ساخت پوشه:

mkdir directoryname

اگر مسیر تودرتو می‌خواهید و پوشه‌های میانی وجود ندارند، با -p همه را یک‌جا بسازید:

mkdir -p /backup/2026/mysql

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

cp file.zip /home/directory/test/
cp -r public_html /backup/public_html

سوئیچ -r برای پوشه‌ها لازم است. برای فایل‌های سایت بهتر است به‌جای آن از -a استفاده کنید؛ این سوئیچ دسترسی‌ها، زمان فایل‌ها و لینک‌های نمادین را حفظ می‌کند و همین موضوع جلوی خطاهای permission بعد از کپی را می‌گیرد (حفظ مالکیت فقط وقتی انجام می‌شود که دستور را با کاربر root بزنید):

cp -a public_html /backup/public_html

انتقال فایل به مسیری دیگر:

mv file.zip /home/directory/test/

اسلش انتهای مسیر مقصد را جدی بگیرید: اگر پوشه‌ی test وجود نداشته باشد و اسلش هم نگذارید، mv خطا نمی‌دهد؛ فایل را با نام test ذخیره می‌کند و شما دنبال فایلی می‌گردید که اسمش عوض شده است. با اسلش انتهایی، در همان حالت خطا می‌گیرید.

همین دستور کار تغییر نام را هم انجام می‌دهد؛ کافی است مقصد به‌جای مسیر، یک نام باشد:

mv file newfile

حواستان باشد که mv و cp اگر فایل مقصد از قبل وجود داشته باشد، بدون هیچ سؤالی رویش می‌نویسند. برای اینکه اول بپرسد، -i را اضافه کنید: mv -i و cp -i.

حذف: جایی که باید دستتان بلرزد

حذف یک فایل:

rm file.zip

در بسیاری از توزیع‌های خانواده‌ی RHEL (CentOS، AlmaLinux، Rocky) برای کاربر root از پیش alias rm='rm -i' تعریف شده و به همین دلیل قبل از حذف تأییدیه می‌گیرد و شما y می‌زنید. این رفتار تضمینی نیست؛ روی خیلی از سرورها، مخصوصاً اوبونتو و دبیان، rm بدون هیچ سؤالی فایل را پاک می‌کند. اگر می‌خواهید همیشه بپرسد، خودتان صریح بنویسید:

rm -i file.zip

برای پوشه‌ها دو دستور دارید. rmdir فقط پوشه‌ی خالی را حذف می‌کند و اگر چیزی داخلش باشد خطا می‌دهد — و همین محدودیت، آن را امن‌ترین گزینه می‌کند:

rmdir directoryname

برای پوشه‌ی پر باید از rm -r استفاده کنید:

rm -r directoryname

و اینجا مهم‌ترین هشدار کل این مقاله: در لینوکس سطل زباله وجود ندارد و چیزی که با rm پاک شود برنمی‌گردد. ترکیب rm -rf نه سؤال می‌پرسد، نه خطا می‌دهد و نه راه بازگشتی دارد. قبل از زدن Enter روی هر دستور حذفی، مسیر را یک بار دیگر بخوانید و مطمئن شوید فاصله‌ی اضافه یا اسلش اول اشتباهی در آن نیست. تنها بیمه‌ی واقعی هم بکاپ سالم و آزموده است.

دانلود فایل مستقیم روی سرور با wget و curl

وقتی می‌خواهید فایلی را روی سرور بیاورید، منطقی‌تر است مستقیم روی خود سرور دانلودش کنید تا اینکه اول روی کامپیوتر خودتان بگیرید و بعد آپلود کنید. ساده‌ترین شکلش:

wget https://site.com/file.zip

به‌جای آدرس بالا لینک مستقیم دانلود را می‌گذارید. دو سوئیچ پرکاربردش: -O برای ذخیره با نام دلخواه و -c برای ادامه‌ی دانلود نیمه‌تمام:

wget -O app.zip "https://site.com/download?id=12"
wget -c https://site.com/bigfile.tar.gz

وقتی آدرس علامت سؤال و پارامتر دارد، آن را داخل کوتیشن بگذارید تا شل آن کاراکترها را تفسیر نکند.

روی نصب‌های مینیمال AlmaLinux، Rocky، CentOS Stream و اوبونتو ممکن است wget اصلاً نصب نباشد. در آن صورت یا نصبش کنید یا از curl استفاده کنید که تقریباً همیشه موجود است:

dnf install wget     # AlmaLinux / Rocky / CentOS Stream
apt install wget     # Ubuntu / Debian

روی CentOS 6 و ۷ این دستور yum install wget بود؛ هر دو نسخه به پایان پشتیبانی رسیده‌اند و روی توزیع‌های جانشین (AlmaLinux و Rocky) دستور dnf است. البته yum هنوز به‌عنوان یک نام مستعار برای dnf کار می‌کند، پس اگر در مستندی به yum برخوردید خطا نمی‌گیرید.

معادل‌های همان کارها با curl:

curl -O https://site.com/file.zip
curl -L -o app.zip "https://site.com/download?id=12"

سوئیچ -O فایل را با همان نام سمت سرور ذخیره می‌کند، -o نام دلخواه می‌گیرد و -L ریدایرکت‌ها را دنبال می‌کند (بدون آن، خیلی از لینک‌های دانلود یک فایل چندبایتی خالی به شما می‌دهند).

دانلود از FTP و نکته‌ی امنیتی‌اش

اگر منبع فایل یک سرور FTP با نام کاربری و رمز باشد، آن آدرس به‌تنهایی یک دستور نیست؛ باید آن را به wget یا curl بدهید:

wget ftp://username:password@XXX.XXX.XXX.XXX/Folder/File.zip

به‌جای XXX.XXX.XXX.XXX آی‌پی و به‌جای username:password نام کاربری و رمز FTP را می‌گذارید. اما بدانید که با این کار رمز شما هم در history شل ذخیره می‌شود و هم تا لحظه‌ی پایان دانلود در خروجی ps برای بقیه‌ی کاربران سرور قابل دیدن است. اگر سرور چند کاربره است، رمز را از خط فرمان بیرون بیاورید و در فایل ~/.netrc با دسترسی 600 بگذارید (wget خودش این فایل را می‌خواند، اما curl فقط وقتی سوئیچ --netrc را بدهید) یا اصلاً سراغ FTP ساده نروید: پروتکل FTP رمزنگاری ندارد و رمز عبور روی شبکه به‌صورت متن ساده رد و بدل می‌شود. جایگزین امن، انتقال روی بستر SSH است:

scp username@XXX.XXX.XXX.XXX:/Folder/File.zip /root/

حالت‌های دیگر انتقال فایل با SSH را در نحوه انتقال فایل از طریق SSH آورده‌ایم.

باز کردن فایل‌های فشرده: tar، zip و بقیه

فایل با پسوند .tar ساده:

tar -xvf file.tar

سه حرف این دستور یعنی x استخراج، v نمایش نام فایل‌ها حین کار و f اعلام اینکه ورودی یک فایل است. برای فرمت .tar.gz سوئیچ z اضافه می‌شود:

tar -xzf file.tar.gz

در نسخه‌های امروزی GNU tar اصلاً لازم نیست نوع فشرده‌سازی را دستی بگویید؛ خودش تشخیص می‌دهد. یعنی این یک دستور برای .tar و .tar.gz و .tar.bz2 و .tar.xz کار می‌کند:

tar -xf file.tar.gz

اگر خواستید صریح باشید: -xjf برای .tar.bz2 و -xJf (با J بزرگ) برای .tar.xz.

دو عادت خوب پیش از استخراج. اول اینکه فهرست محتویات آرشیو را ببینید تا آرشیوی که همه چیز را در مسیر فعلی خالی می‌کند غافلگیرتان نکند:

tar -tf file.tar.gz

دوم اینکه مقصد استخراج را صریح بدهید (پوشه‌ی مقصد باید از قبل وجود داشته باشد):

tar -xzf file.tar.gz -C /var/www/html

برای ساختن آرشیو هم به‌جای x از c استفاده می‌کنید:

tar -czf backup.tar.gz public_html

فرمت zip دستور جداگانه‌ی خودش را دارد:

unzip file.zip

و برای استخراج در مسیر دلخواه یا فقط دیدن فهرست محتویات:

unzip file.zip -d /var/www/html
unzip -l file.zip

ابزار unzip روی نصب‌های مینیمال معمولاً موجود نیست و با dnf install unzip یا apt install unzip نصب می‌شود. بدیهی است که در همه‌ی این دستورها به‌جای file.zip نام فایل خودتان را می‌گذارید.

خواندن فایل‌ها: cat، tac، less، head و tail

دستور cat مخفف Concatenate است و پرکاربردترین راه دیدن محتوای یک فایل در ترمینال:

cat file.txt

می‌تواند چند فایل را پشت سر هم و در یک خروجی چاپ کند:

cat file1.txt file2.txt file3.txt

با سوئیچ -n شماره‌ی خطوط را — شامل خطوط خالی — کنار خروجی می‌گذارد، و با -b فقط خطوط غیرخالی را شماره‌گذاری می‌کند:

cat -n file-all.txt
cat -b file-all.txt

این شماره‌گذاری وقتی به کار می‌آید که وب‌سرور یا PHP در لاگ خطا به شماره‌ی خط یک فایل کانفیگ اشاره کرده و می‌خواهید سریع همان خط را پیدا کنید.

اما cat را روی فایل بزرگ یا باینری اجرا نکنید. کل فایل را بی‌وقفه در ترمینال می‌ریزد و در مورد فایل باینری، کاراکترهای کنترلی‌اش می‌تواند نمایش ترمینال را به هم بریزد (اگر گرفتار شدید، reset بزنید). برای فایل‌های بزرگ less ابزار درست است:

less /var/log/messages

این مسیر مربوط به خانواده‌ی RHEL (AlmaLinux، Rocky، CentOS) است؛ روی دبیان و اوبونتو لاگ عمومی سیستم /var/log/syslog نام دارد. اگر هیچ‌کدام نبود، سرور فقط journald دارد و باید سراغ journalctl بروید.

داخل less با کلیدهای جهت و Page Up/Down حرکت می‌کنید، با / و بعد نوشتن عبارت جست‌وجو می‌کنید و با n به مورد بعدی می‌روید، G به انتهای فایل و g به ابتدای آن می‌برد و با q خارج می‌شوید.

اگر فقط ابتدا یا انتهای فایل را می‌خواهید:

head -n 20 access.log
tail -n 50 error.log

پرکاربردترین حالت tail روی سرور، تماشای زنده‌ی لاگ است. با -f پنجره باز می‌ماند و هر خط جدیدی که به فایل اضافه شود همان لحظه نمایش داده می‌شود؛ عالی برای وقتی که خطایی را روی سایت بازتولید می‌کنید و می‌خواهید هم‌زمان لاگش را ببینید. برای خروج Ctrl+C بزنید:

tail -f /var/log/httpd/error_log

باز هم حواستان به توزیع باشد: مسیر بالا مال آپاچی روی خانواده‌ی RHEL است و روی دبیان و اوبونتو /var/log/apache2/error.log است؛ برای Nginx هم معمولاً /var/log/nginx/error.log.

اگر لاگ در همان حین می‌چرخد (log rotation)، -F بزرگ را استفاده کنید تا tail فایل جدید را دنبال کند و ساکت نماند.

دستور tac؛ همان cat از آخر به اول

دستور tac عملاً وارونه‌ی cat است — چه در نام و چه در کار: فایل را از خط آخر به خط اول چاپ می‌کند.

tac file-all.txt

کاربرد واقعی‌اش روی لاگ‌هاست: تازه‌ترین رخدادها در انتهای فایل‌اند و با tac اول از همه دیده می‌شوند. ترکیب زیر آخرین ۱۰۰ خط لاگ را با جدیدترین خط در بالا نشان می‌دهد:

tail -n 100 error_log | tac

سوئیچ -s (یا --separator) هم دارد، اما کاری که می‌کند اغلب اشتباه توضیح داده می‌شود: این سوئیچ چیزی را فیلتر یا حذف نمی‌کند. فقط جداکننده‌ی رکوردها را از «خط جدید» به رشته‌ای که شما می‌دهید تغییر می‌دهد؛ یعنی tac متن را بر اساس آن رشته تکه‌تکه می‌کند و ترتیب تکه‌ها را برعکس می‌نویسد. برای همین روی داده‌ای مثل یک فهرست جداشده با ویرگول معنا پیدا می‌کند:

tac -s "," names.txt

برای فیلتر کردن خطوط بر اساس یک کلمه، ابزارش tac نیست؛ grep است:

grep "two" file-all.txt
grep -v "two" file-all.txt

اولی فقط خطوط دارای آن عبارت را نشان می‌دهد و دومی با -v برعکس، آن خطوط را کنار می‌گذارد.

ساخت فایل و تغییر مسیر خروجی با > و >>

هر دستوری که چیزی روی صفحه چاپ می‌کند، می‌توانید خروجی‌اش را به‌جای صفحه به یک فایل بفرستید. با یک علامت > فایل مقصد از صفر بازنویسی می‌شود و محتوای قبلی‌اش از بین می‌رود:

cat file1.txt file2.txt file3.txt > file-all.txt

با دو علامت >> محتوا به انتهای فایل مقصد اضافه می‌شود و چیزی پاک نمی‌شود:

cat file4.txt >> file-all.txt

همین یک تفاوت، منبع بخش بزرگی از فاجعه‌های شبانه است: یک > به‌جای >> روی یک فایل کانفیگ، آن را خالی می‌کند. علامت < کار متفاوتی می‌کند و برعکس این دو است؛ فایل را به‌عنوان ورودی به دستور می‌دهد، نه اینکه خروجی را جایی ذخیره کند.

از همین قابلیت می‌شود برای ساخت سریع یک فایل متنی استفاده کرد؛ دستور زیر را بزنید، متن را تایپ کنید و در آخر Ctrl+D را برای ذخیره فشار دهید:

cat > new_file.txt

دو تذکر درباره‌ی این روش. اول اینکه برای کپی کردن محتوای یک فایل در فایلی دیگر (حتی با نام و مسیر جدید) دستور درست cp است؛ اگر با cat این کار را بکنید فقط محتوا منتقل می‌شود و دسترسی‌ها و مالکیت فایل جدید از نو ساخته می‌شوند. دوم اینکه cat > فقط برای ساخت فایل تازه خوب است و امکان ویرایش فایل موجود را ندارد؛ برای ویرایش واقعی سراغ یک ویرایشگر بروید. کار با آن را در نصب و استفاده از ویرایشگر متنی nano توضیح داده‌ایم.

پیدا کردن فایل‌ها

برای پیدا کردن فایل‌ها روی سرور، find کاربردی‌ترین ابزار لینوکس است — از پیدا کردن فایل بر اساس نام و پسوند گرفته تا بر اساس حجم، تاریخ تغییر یا مالک، و حتی اجرای یک دستور روی هر چیزی که پیدا می‌کند. چون خودش یک مقاله‌ی کامل می‌خواهد، نمونه‌های عملی‌اش را جداگانه در ۳۵ نمونه عملی از دستورات find در لینوکس آورده‌ایم.

سریع‌تر شدن: تاریخچه، برچسب‌گذاری دستورها و alias

بخش زیادی از وقتی که پای SSH تلف می‌شود، صرف تایپ دوباره‌ی دستورهای طولانی می‌شود. سه راه‌حل، از ساده به تمیز:

۱. تاریخچه و جست‌وجوی معکوس با Ctrl+R

دستور history فهرست دستورهای قبلی را با شماره نشان می‌دهد و با ! و شماره می‌توانید هرکدام را دوباره اجرا کنید:

history
!142

ولی سریع‌تر از این، جست‌وجوی معکوس است: Ctrl+R را بزنید و چند حرف از دستور را تایپ کنید؛ شل جدیدترین دستور منطبق را نشان می‌دهد. زدن دوباره‌ی Ctrl+R به موارد قدیمی‌تر می‌رود، Enter دستور را اجرا می‌کند، کلید جهت‌نما یا End اجازه می‌دهد قبل از اجرا ویرایشش کنید و Ctrl+G از جست‌وجو بیرون می‌آید بدون اینکه چیزی اجرا شود.

۲. برچسب (Label) گذاشتن روی دستورهای طولانی

حالا فرض کنید دستور طولانی زیر را دارید که برای تشخیص حملات DDoS و شمارش وضعیت اتصال‌های TCP استفاده می‌شود:

netstat -nat | awk '{print $6}' | sort | uniq -c | sort -n

این نسخه‌ی قدیمی است. ابزار netstat بخشی از بسته‌ی منسوخ‌شده‌ی net-tools است و روی توزیع‌های امروزی معمولاً اصلاً نصب نیست. جایگزینش ss از بسته‌ی iproute2 است که به‌صورت پیش‌فرض روی سرور وجود دارد. در خروجی ss ستون State ستون اول است (در netstat ستون ششم بود) و با NR>1 هم خط سرستون را از شمارش کنار می‌گذاریم:

ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c | sort -n

هر کدام از این دو دستور را که استفاده کنید، تایپ دوباره‌شان آزاردهنده است. ترفند برچسب‌گذاری این است که یک کامنت کوتاه به انتهای دستور اضافه کنید. در شل، هر چیزی بعد از # کامنت است و اجرا نمی‌شود، اما عیناً در history ذخیره می‌شود:

ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c | sort -n # ddos

به‌جای ddos هر نام دلخواهی می‌گذارید. از این به بعد کافی است Ctrl+R بزنید و ddos را تایپ کنید تا کل آن دستور برگردد؛ بعد Enter برای اجرا.

دو نکته که این ترفند بدون آن‌ها کار نمی‌کند: دستور باید دست‌کم یک بار اجرا شده باشد تا وارد history شود، و history وقتی روی دیسک نوشته می‌شود که از شل خارج شوید (اگر عجله دارید، history -a همان لحظه ذخیره‌اش می‌کند). ضمناً کامنت‌های تعاملی در bash به‌صورت پیش‌فرض فعال‌اند؛ اگر شل شما zsh است ممکن است لازم باشد اول setopt interactivecomments را اجرا کنید.

۳. alias؛ راه تمیزتر برای همان کار

برچسب و Ctrl+R خوب‌اند، ولی به history وابسته‌اند و history پاک‌شدنی است. راه ماندگارتر، ساختن نام مستعار (alias) است:

alias ll='ls -alh'
alias www='cd /var/www/html'
alias tailerr='tail -f /var/log/httpd/error_log'

از این به بعد نوشتن ll همان ls -alh را اجرا می‌کند. اما alias تعریف‌شده در ترمینال فقط تا بستن همان نشست زنده است؛ برای ماندگاری باید همین خط‌ها را در انتهای فایل ~/.bashrc بگذارید و یک بار بخوانیدشان:

source ~/.bashrc

دو محدودیت alias را بدانید: نمی‌تواند ورودی (آرگومان) بگیرد، و اگر خود دستور پر از کوتیشن باشد — مثل همان دستور awk بالا — تعریف alias برایش دردسر می‌شود. راه‌حل هر دو مورد، تعریف یک تابع شل به‌جای alias در همان ~/.bashrc است:

ddos() {
  ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c | sort -n
}

حالا با تایپ ddos همان گزارش را می‌گیرید، بدون هیچ درگیری با کوتیشن‌ها.

چند عادت که سرور را نجات می‌دهد

عملیات طولانی مثل استخراج یک آرشیو چندگیگابایتی یا گرفتن بکاپ را داخل یک نشست پایدار اجرا کنید؛ در غیر این صورت قطع شدن اینترنت شما وسط کار، دستور را روی سرور نصفه‌کاره می‌کشد. ابزارش screen است که در دستور Screen در لینوکس توضیح داده شده است.

عادت دوم، نگاه کردن به این است که چه کسی و از کجا به سرور وارد شده؛ دستورهایش را در بررسی لاگ آخرین ورودها به لینوکس آورده‌ایم و برای دیدن اینکه رمز هر کاربر آخرین بار کی عوض شده هم لیست آخرین پسورد تغییر یافته کاربران ssh را ببینید. برای عیب‌یابی شبکه و بررسی دسترسی به سرور هم ابزارهای networking در SSH مجموعه‌ی جداگانه‌ای از همین خط فرمان است.

و در آخر، سه قاعده‌ای که هیچ‌وقت کهنه نمی‌شوند: قبل از حذف یا بازنویسی، مسیر را دوباره بخوانید؛ قبل از هر تغییر روی فایل کانفیگ، یک کپی با cp از آن بگیرید؛ و به‌جای حفظ کردن سوئیچ‌ها، برای هر دستوری که مطمئن نیستید man آن را باز کنید — مثلاً man tar. راهنمای رسمی هر ابزار همیشه به‌روزتر از هر مقاله‌ای است.