Linux watch 指令完整用法與常見陷阱
學會調整 watch 間隔、用 -d 標示輸出差異、以 -g 在變更時結束,並正確引用含 pipe 的 shell 指令,避免只重複執行第一段。
watch 指令的作用
watch 指令會以固定間隔重新執行另一個指令,並在螢幕上的相同位置重繪輸出。預設間隔為 2 秒。當您等待某個數值變化時,可以使用此指令,例如磁碟空間逐漸用滿、容器完成穩定、憑證續期完成,或佇列逐漸清空。
watch 來自 procps-ng,Ubuntu 或 Debian VPS 全新安裝時,已隨 procps 套件一併安裝。使用下列任何 flag 前,請先確認版本,因為其中 2 個實用選項是近期才加入的。
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 則會改為截斷長行;超出最底列的內容完全不會繪製。畫面內沒有捲動歷程,因為每個週期都會覆寫上一個畫面。這項特性決定了 watch 最適合處理哪些工作。
watch 應該多久重新執行一次命令?
2 秒只是預設值。請根據數值變化速度及每次執行的成本選擇間隔。
-n 0.5適合持續變化的計數器,例如ss -s或介面位元組計數。watch 接受的最小間隔為 0.1 秒。-n 30或-n 60適合磁碟與憑證。一天才填滿的檔案系統,不需要每分鐘顯示 30 個畫面。
watch 會執行命令,等待命令完成後,才依指定間隔休眠。因此,命令執行時間會加到間隔中。例如,在 -n 2 下,若命令需要 8 秒,畫面會每 10 秒更新一次,且整段期間都會持續占用系統資源。加入 -p(--precise)後,watch 會改為以每次執行的開始時間為基準,目標是在每隔指定秒數時開始下一次執行。
如果您希望永久使用不同的預設值,請在 shell profile 中匯出 WATCH_INTERVAL。明確指定的 -n 仍會覆寫此設定。執行 watch --help,確認您的版本會讀取該變數。
使用 -d 標示變更
要從一大段相同文字中找出唯一移動的欄位並不容易。-d(--differences)會代為處理。
watch -n 30 -d 'df -h / /var'與前一個畫面不同的字元會以反白顯示,因此 Use% 儲存格一移動就會亮起,其他內容則維持不變。如果 /var 不是獨立的檔案系統,您會看到 root 檔案系統列出兩次。這是快速了解該主機分割方式的方法。
比較是依位置進行的,也就是將新畫面與舊畫面逐字元對照。欄寬會變動的輸出幾乎整行都會亮起,因此請優先使用版面固定的命令。目前的 procps-ng 也接受 watch --differences=permanent,會保留所有曾經變更的位置,而不只標示最近一次變更。依賴此功能前,請使用 watch --help 確認。
如何在輸出變更時讓 watch 結束?
-g (--chgexit) 會在輸出第一次與前一次執行結果不同時停止 watch。命令提示字元會重新出現,因此您可以在同一行的後面繼續輸入內容。
watch -n 10 -g 'systemctl is-active myapp' ; echo 'state changed'這個旗標會將 watch 變成「部署完成時通知我」的工具。但其中有一個陷阱,而且很容易遇到:比較範圍涵蓋完整輸出,因此其中任何時鐘或 PID (process identifier) 都會在第一次重新整理時變更,導致 watch 立即結束。systemctl status myapp 會輸出經過時間與記憶體使用量,因此對它使用 -g 沒有意義。請將命令縮減為您等待的唯一穩定資訊,這正是 systemctl is-active 所提供的內容。
較新的 procps-ng 也加入相反的測試 --equexit <cycles>,當輸出連續指定週期維持不變後結束。它可回答「這項工作何時會停止變動」。請檢查 watch --help,因為較舊的組建不支援此功能。
為什麼 watch 會忽略管線和 glob?
這是每個人都會遇到一次的問題,原因在於 shell,而不在 watch。
watch docker compose ps | grep web互動式 shell 會先讀取整行,然後在管線符號處切分指令。它會啟動 watch docker compose ps,並將 watch 自身的畫面輸出 連接到 grep。此時 watch 不再寫入終端機,因此畫面會錯誤或空白,而 grep 篩選的是重新繪製的輸出,不是容器清單。
請將整個管線加上引號,讓它以單一引數傳入。
watch 'docker compose ps | grep web'watch 會將這個字串傳給 sh -c,再由該 shell 每個週期執行一次管線。glob 也遵循相同規則,但症狀較不明顯。
watch ls -l /var/log/*.log
watch 'ls -l /var/log/*.log'第一行會在你按下 Enter 時,由 shell 只展開一次 glob。之後 watch 會重複執行這份固定的檔名清單,因此一分鐘後建立的 log 檔案不會出現。第二行則會將 glob 傳給 watch,再由 sh 在每個週期內展開,因此新檔案會自動出現。
引號也會決定變數或命令替換的求值時機。watch "echo $(date)" 會在 shell 中執行 date 一次,之後永遠回顯該固定字串。watch 'echo $(date)' 則會在每個週期執行 date。單引號表示稍後求值。雙引號表示立即求值。
這個 sh -c 還有兩個影響:
- 別名和 shell 函式不會存在於其中。
watch ll會因sh: 1: ll: not found而失敗,因為sh -c不會讀取你的.bashrc。請直接寫出實際指令,或提供只存在於互動式PATH中之 binary 的完整路徑。 - 建議擷取標準錯誤。需要讓錯誤文字排列在畫面中,而不是散落在畫面各處時,請將
2>&1放在引號內。
引號變得難以處理時,-x(--exec)會直接執行指令,不經由 sh -c。含有空格的引數會更容易處理,但管線和 glob 會完全失效,因為已沒有 shell 可供解譯。
權限遵循相同邏輯,因為 watch 是一般程序。watch 'sudo ss -tulpn' 會出現你看不到、也無法輸入的密碼提示。請改為執行 sudo watch 'ss -tulpn',並記住在按下 Ctrl+C 前,整個迴圈都會以 root 身分執行。
VPS 上值得監看的 4 件事
正在填滿的磁碟
watch -n 30 -d 'df -h / /var'df 會向核心要求已持有的數值,因此可以持續重複執行,成本很低。du -sh /var/log 則不同,因為它每次循環都會遍歷目錄樹中的每個檔案。在 watch 下執行時,它會持續讀取磁碟,拖慢你正在診斷的機器。執行一次 du,或使用 ncdu,然後讓 df 持續監看,確認數值是否仍在上升。
持續重新啟動的容器
cd /srv/myapp
watch -n 5 -d 'docker compose ps'狀態欄會顯示每個容器已執行多久。陷入當機循環的容器會一直重設為 "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 中執行。請注意,它監看的是磁碟上的憑證。執行中的 Web 伺服器會將舊憑證保留在記憶體中,直到重新載入為止,因此請使用 echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -enddate 檢查實際提供的憑證;不要以 2 秒的間隔,對公開主機執行該命令。續期本身由 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 在這裡就達到限制。它只會比較目前畫面與前一個畫面,無法測試條件,因此永遠無法告訴你「計數已達到 0」。一般的 shell 迴圈可以做到,使用 命令替換 在每次迭代擷取計數:
until [ "$(find /srv/queue/incoming -type f | wc -l)" -eq 0 ]; do sleep 5; done; echo 'queue drained'watch 指令不適用的情況
watch 會重複執行指令,不會記住上一次的執行結果,也不知道該指令的用途。這對 df 沒問題,但在以下 4 種情況下不適用。
- 日誌。 watch 會重繪固定畫面,因此兩次週期之間出現並捲動消失的行會遺失。請使用
journalctl -fu nginx或tail -f;這些工具會在新行寫入時持續串流顯示。 - 耗用大量資源的指令。
du -sh /或對繁忙資料庫執行的查詢,會在任何設定的間隔下持續造成背景負載,因為 watch 會不斷重新啟動它。 - 任何具有副作用的操作。 會寫入資料、發送請求、重新啟動或安裝軟體的指令,會在每個週期重複執行。每 2 秒對 API 執行一次
curl,每天會產生 43,200 個請求,這可能導致免費 API key 被停用。 - 長期執行的檢查。 watch 會在終端機中執行,工作階段結束時也會停止。它不會發出警示,關閉筆記型電腦後也不會保留歷史記錄。這種情況應使用真正的狀態監控工具,例如 Uptime Kuma,或在伺服器上持續執行的排程檢查。
判斷界線在於執行時間。watch 適合用於等待某件特定事情發生的 10 分鐘。任何明天仍應持續執行的檢查,都應改用排程計時器或真正的監控工具。
在 SSH 中使用 watch 時,請放在 tmux 內執行
透過 SSH 執行時,watch 的持續性取決於連線是否維持。連線中斷後,shell 會收到 SIGHUP,watch 也會隨之結束。tmux 可避免這種情況,讓 watch 真正適合在遠端主機上使用。
tmux new -As ops
watch -n 30 -d 'df -h /'按下 Ctrl+b,再按 d 可分離工作階段。迴圈會繼續在伺服器上執行。稍後重新連線後,使用 tmux attach -t ops 即可恢復工作階段,畫面仍會持續更新,標頭中的時鐘也能證明這一點。分割視窗後,可以在一側保留 watch,另一側保留 journalctl -f;這正是以 tmux 為基礎的終端機工作台的用途。若相同問題同時適用於多台主機,應使用專為管理多台 Linux 伺服器打造的工具,而不是建立大量 watch 窗格。
此處引用的畫面僅供示意。不同發行版與 procps-ng 版本的欄位配置和版本字串可能不同,因此請在自己的機器上閱讀 man watch,確認該版本實際支援的旗標。
FAQ
為什麼 watch 會忽略 watch mycmd | grep foo 中的管線?
在 watch 啟動前,shell 就會先依管線符號分割這一行。因此,管線實際上會將 watch 自己繪製的畫面傳給 grep,而不會篩選命令的輸出。請將整個管線加上引號:watch 'mycmd | grep foo'。watch 會將這個單一引數傳給 sh -c,由它在每個週期執行一次管線。萬用字元和命令替換也適用相同規則。
使用 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 不行。若要等待實際條件,例如計數降至零,請使用 shell until 迴圈,因為 watch 只能偵測輸出是否變更。
為什麼 watch 對 shell 中可正常執行的項目顯示 command not found?
watch 會將命令傳給 sh -c,而該 shell 不會讀取 .bashrc,因此其中的別名和 shell 函式在該環境中不存在。這則訊息通常是 sh: 1: ll: not found。請直接寫出實際命令;如果二進位檔只位於互動式 PATH 中,請使用其完整路徑。