آموزش کامل دستور watch در لینوکس و کاربرد آن
با دستور watch در لینوکس هر دستوری را در فواصل زمانی مشخص اجرا کنید. یاد بگیرید چگونه با فلگهای n- و d- تغییرات خروجی را هایلایت کرده و با کوتیشنگذاری صحیح از pipe استفاده کنید.
عملکرد دستور watch
دستور watch یک دستور دیگر را در فواصل زمانی مشخص دوباره اجرا کرده و خروجی آن را در همان جای قبلی روی صفحه بازنویسی میکند. فاصله زمانی پیشفرض دو ثانیه است. هرگاه منتظر تغییر یک عدد هستید، از این دستور استفاده کنید: پر شدن دیسک، آماده شدن یک container، دریافت گواهی جدید یا خالی شدن یک صف.
ابزار watch بخشی از بسته procps-ng است و بهصورت پیشفرض روی یک VPS تازه نصبشده با Ubuntu یا Debian به عنوان بخشی از بسته procps وجود دارد. پیش از اعتماد به هر یک از فلگهای زیر، نسخه خود را بررسی کنید، زیرا دو مورد از گزینههای کاربردی آن جدید هستند.
watch --versionدر Ubuntu 24.04، این دستور خطی مشابه watch from procps-ng 4.0.4 چاپ میکند. اکنون سادهترین مثال کاربردی را ببینید.
watch df -h /صفحه پاک شده و یک خط سربرگ، یک خط خالی و سپس خروجی df -h / نمایش داده میشود:
Every 2.0s: df -h / server1: Sun Aug 9 10:21:44 2026در سمت چپ، فاصله زمانی و دستور دقیقی که watch در حال اجرای آن است دیده میشود. در سمت راست، نام میزبان (hostname) و زمان فعلی قرار دارد. ساعت، نیمه کاربردی صفحه است، زیرا ثابت میکند که صفحه همچنان در حال بهروزرسانی است، حتی اگر اعداد زیر آن تغییری نکنند. برای خروج، کلیدهای Ctrl+C را فشار دهید.
دستور watch یک فریم متناسب با ترمینال ترسیم میکند. خطوط طولانی شکسته میشوند، اما -w آنها را برش میدهد و هر چیزی که فراتر از ردیف پایین باشد، اصلاً نمایش داده نمیشود. هیچ قابلیت اسکرول به عقب (scrollback) در داخل این فریم وجود ندارد، زیرا هر چرخه، چرخه قبلی را بازنویسی میکند. همین یک واقعیت، تعیینکننده اصلی موارد استفاده از watch است.
دستور watch هر چند وقت یکبار باید اجرا شود؟
دو ثانیه فقط مقدار پیشفرض است. بازه زمانی را بر اساس سرعت تغییر مقادیر و هزینه اجرای دستور انتخاب کنید.
-n 0.5برای شمارندههایی که دائماً در حال تغییر هستند، مانندss -sیا تعداد بایتهای رابط شبکه. کوچکترین بازهای که watch میپذیرد 0.1 ثانیه است.-n 30یا-n 60برای دیسکها و گواهیها. فایلسیستمی که در طول یک روز پر میشود، نیازی به سی فریم در دقیقه ندارد.
دستور watch ابتدا فرمان را اجرا میکند، منتظر پایان آن میماند و سپس به اندازه بازه تعیینشده میخوابد. زمان اجرا به فاصله زمانی اضافه میشود؛ بنابراین دستوری که تحت -n 2 هشت ثانیه طول میکشد، هر ده ثانیه یک فریم به شما میدهد و دستگاه را در تمام مدت درگیر نگه میدارد. با افزودن -p (--precise)، دستور watch تلاش میکند تا هر بازه ثانیه یکبار اجرا را شروع کند؛ این زمان از شروع یک اجرا تا شروع اجرای بعدی اندازهگیری میشود.
اگر همیشه مقدار پیشفرض متفاوتی میخواهید، WATCH_INTERVAL را در shell profile خود export کنید. یک -n صریح همچنان بر آن اولویت دارد. برای اطمینان از اینکه build شما این متغیر را میخواند، watch --help را اجرا کنید.
برجسته کردن تغییرات با استفاده از -d
خواندن حجم زیادی از متنهای مشابه برای پیدا کردن فیلدی که تغییر کرده است، کار دشواری است. -d (--differences) این کار را برای شما انجام میدهد.
watch -n 30 -d 'df -h / /var'کاراکترهایی که نسبت به فریم قبلی متفاوت هستند با ویدئوی معکوس (reverse video) نمایش داده میشوند، بنابراین سلول Use% به محض تغییر روشن میشود و بقیه موارد ثابت میمانند. اگر /var یک فایلسیستم مجزا نباشد، فایلسیستم ریشه را دو بار مشاهده خواهید کرد که روشی سریع برای درک نحوه پارتیشنبندی سرور است.
مقایسه به صورت موقعیتی انجام میشود، به این معنی که watch فریم جدید را کاراکتر به کاراکتر با فریم قدیمی تطبیق میدهد. خروجیهایی که عرض ستونهایشان تغییر میکند تقریباً به طور کامل روشن میشوند، بنابراین دستوراتی را ترجیح دهید که چیدمان ثابتی دارند. نسخه فعلی procps-ng از watch --differences=permanent نیز پشتیبانی میکند که به جای نمایش تنها آخرین تغییر، تمام موقعیتهایی را که تاکنون تغییر کردهاند، برجسته نگه میدارد. پیش از تکیه بر آن، عملکردش را با watch --help تأیید کنید.
چگونه watch را تنظیم کنم تا با تغییر خروجی متوقف شود؟
-g (--chgexit) باعث میشود watch به محض اینکه خروجی با اجرای قبلی تفاوت پیدا کرد، متوقف شود. در این حالت خط فرمان (prompt) شما بازمیگردد، بنابراین میتوانید دستور دیگری را در همان خط پس از آن قرار دهید.
watch -n 10 -g 'systemctl is-active myapp' ; echo 'state changed'این همان فلگی است که watch را به ابزاری برای «اطلاعرسانی هنگام اتمام استقرار (deploy)» تبدیل میکند. این ابزار یک تله دارد که همه در آن گرفتار میشوند: مقایسه کل خروجی را در بر میگیرد، بنابراین هر ساعت یا PID (شناسه پردازش) که در خروجی باشد، در همان اولین بازخوانی تغییر میکند و watch بلافاصله خارج میشود. دستور systemctl status myapp زمان سپریشده و میزان مصرف حافظه را چاپ میکند، بنابراین استفاده از -g روی آن بیفایده است. دستور را به همان یک مورد ثابت که منتظرش هستید محدود کنید، که این دقیقاً همان کاری است که systemctl is-active برای شما انجام میدهد.
نسخههای جدیدتر procps-ng تست معکوس --equexit <cycles> را اضافه کردهاند که پس از ثابت ماندن خروجی برای آن تعداد چرخه، خارج میشود. این قابلیت به پرسش «به من بگو چه زمانی این وضعیت آرام میشود» پاسخ میدهد. نسخه watch --help خود را بررسی کنید، زیرا بیلدهای قدیمیتر این قابلیت را ندارند.
چرا watch لوله (pipe) و glob من را نادیده میگیرد؟
این خطایی است که همه یکبار با آن مواجه میشوند و علت آن در shell شما نهفته است، نه در watch.
watch docker compose ps | grep webshell تعاملی شما کل خط را پیش از اجرا میخواند و آن را در محل لوله (pipe) تقسیم میکند. این کار باعث میشود watch docker compose ps اجرا شده و خروجی صفحهٔ خودِ watch به grep متصل شود. در این حالت watch دیگر به ترمینال نمینویسد، بنابراین نمایشگر خراب یا خالی است و grep بهجای لیست کانتینرها، خروجی بازترسیم (redraw) را فیلتر میکند.
کل خط لوله (pipeline) را داخل کوتیشن قرار دهید تا بهعنوان یک آرگومان واحد ارسال شود.
watch 'docker compose ps | grep web'watch آن رشته را به sh -c میفرستد و آن shell، خط لوله را در هر چرخه اجرا میکند. در مورد globها نیز همین قاعده با علائم خفیفتری صدق میکند.
watch ls -l /var/log/*.log
watch 'ls -l /var/log/*.log'خط اول، glob را یکبار در shell شما و در لحظهای که کلید Enter را میزنید، بسط میدهد. سپس watch لیستی ثابت از نام فایلها را اجرا میکند، بنابراین فایل لاگی که یک دقیقه بعد ایجاد شود، هرگز نمایش داده نمیشود. خط دوم، glob را به watch میدهد که آن را در هر چرخه داخل sh بسط میدهد، بنابراین فایلهای جدید بهطور خودکار ظاهر میشوند.
کوتیشنها همچنین تعیین میکنند که یک متغیر یا جایگزینی دستور (command substitution) چه زمانی ارزیابی شود. watch "echo $(date)" دستور date را یکبار در shell شما اجرا کرده و سپس آن رشتهٔ ثابت را برای همیشه تکرار میکند. watch 'echo $(date)' دستور date را در هر چرخه اجرا میکند. کوتیشن تکی (Single quotes) به معنای ارزیابی در آینده و کوتیشن دوتایی (Double quotes) به معنای ارزیابی در همین لحظه است.
دو پیامد دیگر از استفاده از sh -c:
- نامهای مستعار (Aliases) و توابع shell در داخل آن وجود ندارند.
watch llبا خطایsh: 1: ll: not foundمواجه میشود، زیراsh -cهرگز فایل.bashrcشما را نمیخواند. دستور اصلی را بنویسید یا مسیر کامل باینری را که فقط درPATHتعاملی شما موجود است، وارد کنید. - ثبت خروجی خطای استاندارد (Standard error) مفید است. اگر میخواهید متن خطا در قاب نمایش داده شود و در صفحه پخش نشود،
2>&1را داخل کوتیشنها قرار دهید.
هنگامی که استفاده از کوتیشن دشوار میشود، -x (--exec) دستور را مستقیماً و بدون عبور از sh -c اجرا میکند. در این حالت، کار با آرگومانهای دارای فاصله آسانتر میشود، اما لولهها و globها کاملاً از کار میافتند، زیرا دیگر shellای برای تفسیر آنها وجود ندارد.
سطح دسترسیها نیز از همین منطق پیروی میکنند، زیرا watch یک پردازش معمولی است. watch 'sudo ss -tulpn' با درخواست رمز عبوری مواجه میشود که شما نمیتوانید آن را ببینید یا در آن تایپ کنید. بهجای آن sudo watch 'ss -tulpn' را اجرا کنید و به یاد داشته باشید که کل حلقه تا زمانی که Ctrl+C را فشار ندهید، با دسترسی root اجرا میشود.
چهار مورد که ارزش نظارت بر روی VPS را دارند
دیسکی که در حال پر شدن است
watch -n 30 -d 'df -h / /var'دستور df از هسته (kernel) آماری را میخواهد که از قبل در اختیار دارد، بنابراین اجرای مداوم آن هزینه کمی دارد. اما du -sh /var/log چنین نیست، زیرا در هر چرخه تمام فایلهای موجود در درخت دایرکتوری را پیمایش میکند. در حالت watch، این دستور بهطور مداوم دیسک را میخواند و ماشینی که قصد عیبیابی آن را دارید، کند میکند. دستور du را یکبار اجرا کنید یا از ncdu استفاده کنید، سپس df را در حالت watch بگذارید تا به شما بگوید آیا عدد مربوطه همچنان در حال افزایش است یا خیر.
کانتینری که مدام در حال راهاندازی مجدد است
cd /srv/myapp
watch -n 5 -d 'docker compose ps'ستون status نشان میدهد هر کانتینر چه مدت فعال بوده است. کانتینری که در حلقه crash قرار دارد، مدام به وضعیت "Up 2 seconds" باز میگردد و -d این موضوع را در یک نگاه آشکار میکند. ابتدا دایرکتوری را تغییر دهید، زیرا watch دایرکتوری کاریِ shellای که آن را اجرا کرده به ارث میبرد و docker compose به دایرکتوری پروژه خود نیاز دارد. دستور watch به شما میگوید که راهاندازی مجدد در حال وقوع است. دستور docker compose logs -f web دلیل آن را میگوید. هنگامی که دلیل را دانستید، پاسخ را به یک Compose healthcheck که کانتینر را برای شما ریاستارت میکند تبدیل کنید تا نیازی نباشد کسی بنشیند و به صفحه نمایش خیره شود.
رسیدن زمان تمدید گواهی
sudo -i
watch -n 60 -g 'openssl x509 -noout -enddate -in /etc/letsencrypt/live/example.com/fullchain.pem'این دستور تنها یک خط، یعنی notAfter=Nov 7 09:14:22 2026 GMT را چاپ میکند و هیچ چیز دیگری نمایش نمیدهد، بنابراین -g دقیقاً زمانی که فایل با یک نسخه تمدید شده جایگزین شود، فعال میگردد. فایلهای موجود در /etc/letsencrypt/live فقط توسط root قابل خواندن هستند، به همین دلیل این دستور در یک root shell اجرا میشود. توجه داشته باشید که این دستور گواهی موجود روی دیسک را نظارت میکند. وبسرور در حال اجرا، گواهی قدیمی را تا زمان reload در حافظه نگه میدارد، بنابراین با استفاده از echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -enddate بررسی کنید که واقعاً چه چیزی سرو میشود؛ و آن دستور را با بازه زمانی دو ثانیهای روی یک میزبان عمومی اجرا نکنید. خودِ فرآیند تمدید مربوط به یک systemd service و timer است و systemctl list-timers نشان میدهد که چه زمانی دفعه بعد اجرا خواهد شد.
تخلیه صف
watch -n 15 'postqueue -p | tail -n 1'این دستور یک خط خلاصه مانند -- 24 Kbytes in 6 Requests. یا پس از اتمام کار، Mail queue is empty را چاپ میکند. همین الگو برای هر صفی که بتوانید آن را بشمارید کار میکند: watch -n 5 'find /srv/queue/incoming -type f | wc -l'.
در اینجا watch به محدودیت خود میرسد. این ابزار یک فریم را با فریم قبلی مقایسه میکند و نمیتواند یک شرط را تست کند، بنابراین هرگز نمیتواند به شما بگوید "شمارش به صفر رسید". یک حلقه ساده در shell میتواند این کار را با استفاده از جایگزینی دستور (command substitution) برای ثبت تعداد در هر مرحله انجام دهد:
until [ "$(find /srv/queue/incoming -type f | wc -l)" -eq 0 ]; do sleep 5; done; echo 'queue drained'چه زمانی دستور watch ابزار مناسبی نیست
دستور watch فرمان شما را بدون داشتن حافظهای از اجرای قبلی و بدون درک ماهیت آن دستور، مجدداً اجرا میکند. این رفتار برای df مناسب است، اما در چهار موقعیت زیر اشتباه است:
- لاگها. دستور watch یک قاب ثابت را بازترسیم میکند، بنابراین خطوطی که بین دو چرخه ظاهر شده و اسکرول میشوند، از دست میروند. از
journalctl -fu nginxیاtail -fاستفاده کنید که خطوط جدید را همزمان با نوشته شدن، استریم میکنند. - دستورات سنگین. اجرای
du -sh /یا یک کوئری روی دیتابیس شلوغ، با هر بازه زمانی به یک بار پردازشی دائمی در پسزمینه تبدیل میشود، زیرا watch مدام آن را از نو شروع میکند. - هر چیزی که عوارض جانبی دارد. دستوری که مینویسد، پست میکند، ریاستارت میکند یا نصب میکند، در هر چرخه دوباره این کار را انجام خواهد داد. اجرای یک
curlروی یک API هر دو ثانیه یکبار، معادل 43,200 درخواست در روز است که باعث مسدود شدن کلید API رایگان شما میشود. - بررسیهای طولانیمدت. دستور watch در ترمینال شما اجرا میشود و با پایان نشست (session) شما متوقف میگردد. این دستور به کسی هشدار نمیدهد و پس از بستن لپتاپ، هیچ تاریخی از وضعیت نگه نمیدارد. برای این منظور، شما به یک مانیتور وضعیت واقعی مانند Uptime Kuma یا یک بررسی زمانبندیشده که روی سرور باقی میماند، نیاز دارید.
مرز صادقانه در اینجا «زمان» است. دستور watch برای ده دقیقهای است که صرف انتظار برای وقوع یک اتفاق خاص میکنید. هر چیزی که قرار است فردا هم بررسی شود، باید در یک تایمر زمانبندیشده یا یک مانیتور واقعی قرار بگیرد.
اجرای watch داخل tmux هنگام اتصال از طریق SSH
هنگام اتصال از طریق SSH، پایداری دستور watch به پایداری اتصال وابسته است. با قطع شدن لینک، shell شما سیگنال SIGHUP دریافت کرده و دستور watch را نیز متوقف میکند. tmux این مشکل را حل میکند و همان چیزی است که watch را در یک سرور راه دور واقعاً کاربردی میسازد.
tmux new -As ops
watch -n 30 -d 'df -h /'برای جدا شدن (detach)، کلیدهای Ctrl+b و سپس d را فشار دهید. حلقه در سرور همچنان در حال اجرا باقی میماند. بعداً با استفاده از tmux attach -t ops دوباره متصل شوید؛ خواهید دید که فریم همچنان در حال بهروزرسانی است و ساعت موجود در هدر، گواه این موضوع است. پنجره را تقسیم کنید تا بتوانید watch را در یک سمت و journalctl -f را در سمت دیگر داشته باشید؛ این دقیقاً همان ایدهای است که پشت یک محیط کاری ترمینال مبتنی بر tmux قرار دارد. وقتی یک پرسش مشابه برای چندین سرور مطرح است، این کار وظیفه ابزاری است که برای مدیریت چندین سرور لینوکسی ساخته شده، نه ایجاد دیواری از پنجرههای watch.
تصاویر نمایش داده شده در اینجا صرفاً جنبه آموزشی دارند. چیدمان ستونها و رشتههای نسخه در توزیعهای مختلف و نسخههای procps-ng متفاوت است، بنابراین برای اطلاع از فلگهایی که در نسخه شما واقعاً وجود دارند، man watch را در سیستم خود مطالعه کنید.
FAQ
چرا watch در watch mycmd | grep foo از pipe صرفنظر میکند؟
شل شما پیش از آنکه watch اجرا شود، خط را در محل pipe جدا میکند؛ بنابراین خروجیِ ترسیمِ صفحه توسط watch به grep پایپ میشود و خروجی دستور اصلی هرگز فیلتر نمیشود. کل pipeline را داخل کوتیشن قرار دهید: watch 'mycmd | grep foo'. در این حالت، watch آن آرگومان واحد را به sh -c میسپارد و pipeline در هر چرخه یکبار اجرا میشود. همین قاعده برای globها و جایگزینی دستور (command substitution) نیز صدق میکند.
چه بازه زمانی (interval) را باید برای watch انتخاب کنم؟
آن را با سرعت تغییر مقادیر و هزینه اجرای دستور هماهنگ کنید. نیمثانیه برای شمارندههای سریع مناسب است و 0.1 ثانیه کوچکترین بازهای است که watch میپذیرد. بازه 30 تا 60 ثانیه برای دیسکها و گواهیها مناسب است. زمان اجرای دستور به فاصله زمانی اضافه میشود، مگر اینکه از -p استفاده کنید؛ در این صورت، یک دستور کند تحت -n 1 بلافاصله و بدون وقفه تکرار میشود.
آیا watch میتواند یک فایل لاگ را دنبال کند؟
خیر. watch هر بار یک فریم را بازترسیم میکند و هیچ تاریخی از آن نگه نمیدارد؛ بنابراین هر خطی که بین دو چرخه ظاهر شود و اسکرول شود، برای همیشه از دست میرود. journalctl -fu <unit> و tail -f خطوط جدید را به محض رسیدن استریم میکنند که برای لاگها ضروری است. از watch برای مقادیری استفاده کنید که وضعیت فعلی دارند، مانند درصد فضای دیسک یا طول یک صف.
چگونه watch را متوقف کنم تا زمانی که اتفاق مورد نظرم رخ دهد؟
از -g (--chgexit) استفاده کنید و دستوری به آن بدهید که خروجیاش تا زمان وقوع آن رویداد ثابت بماند. خروجیهایی که شامل ساعت یا PID هستند در اولین بازخوانی تغییر کرده و بلافاصله خارج میشوند، بنابراین systemctl is-active myapp در جایی کار میکند که systemctl status myapp کار نمیکند. برای یک شرط واقعی، مانند رسیدن شمارش به صفر، از یک حلقه until در شل استفاده کنید، زیرا watch فقط میتواند تغییر خروجی را تشخیص دهد.
چرا watch برای دستوری که در شل من کار میکند، خطای command not found میدهد؟
watch دستور را به sh -c میسپارد و آن شل، فایل .bashrc را نمیخواند؛ بنابراین aliasها و توابع شل شما در آنجا وجود ندارند. پیام خطا معمولاً sh: 1: ll: not found است. دستور اصلی را بنویسید یا از مسیر کامل (full path) برای باینریهایی استفاده کنید که فقط در PATH تعاملی شما قرار دارند.