Updated: 4 November 2026 · Applies to: watch from procps-ng 4.0.4 on Ubuntu 26.04 and 24.04, Debian 13 and AlmaLinux 10 (procps-ng 3.3.17 on AlmaLinux 9); Bash loops and systemd timers tested on Ubuntu 26.04
To run a Linux command again and again every few seconds, use the watch command: watch -n 5 COMMAND runs COMMAND every 5 seconds and redraws its output on a clean screen until you press Ctrl+C. Without -n, watch repeats the command every 2 seconds. If you need normal scrolling output, a log file or a job that keeps running after you log out, use a while loop with sleep, or a systemd timer when it must also survive a reboot. Cron does not help here: its smallest step is one minute.
How to use the watch command
- Type
watchfollowed by the command you want to repeat:watch free -m
- watch clears the screen, runs the command and shows a header with the interval, the command, the host name and the time. This is lab output from our Ubuntu 26.04 test container (the memory figures belong to the test machine):
Every 2.0s: free -m vps: Sat Oct 10 13:35:05 2026 total used free shared buff/cache available Mem: 3818 953 226 71 2993 2865 Swap: 1199 6 1193 - The screen refreshes in place every 2 seconds. Press Ctrl+C to stop; watch then exits with status 0.
watch is part of the procps package (procps-ng on AlmaLinux, Rocky Linux and RHEL). It was already present in the Ubuntu 24.04 and 26.04 images we tested, but not in the minimal AlmaLinux 9 and 10 or Debian 13 container images. If your server does not have it:
sudo apt install procps # Ubuntu, Debian sudo dnf install procps-ng # AlmaLinux, Rocky Linux, RHEL, Fedora
Set the interval with -n
watch -n 5 uptime watch -n 0.5 df -h /
The interval is in seconds and may be a fraction. watch does not go below 0.1 seconds: when we ran watch -n 0.01 date, the header showed Every 0.1s: date. According to the watch manual, the WATCH_INTERVAL environment variable sets your own default; with WATCH_INTERVAL=5 our test header read Every 5.0s.
Commands with pipes, quotes and aliases
watch hands the command to sh -c. Put anything with a pipe, a redirect or a semicolon in single quotes, so the whole line runs on every update:
watch -n 1 'ls /etc | wc -l'
Without the quotes, your own shell takes the pipe and sends the output of watch itself to wc. Aliases and shell functions are not available inside sh -c: in our test watch ll only showed sh: 1: ll: not found, so write the full command (ls -l). With -x, watch runs the command directly without a shell, which saves quoting for simple commands: watch -x ls -l /var/log.
Highlight what changed with -d
watch -d -n 1 'ss -tn state established'
-d (--differences) shows the characters that changed since the previous update in reverse video. In our test with watch -d date +%S, only the digit that changed was highlighted. --differences=permanent keeps highlighting everything that has changed since the first run.
Let watch stop by itself: -g, -e and -q
- -g (
--chgexit): exit as soon as the output changes. Handy for waiting on a file, a DNS change or a service, and you can chain the next command. In our test,watch -g -n 1 'ls /tmp/flag 2>&1'exited with status 0 once we created the file:watch -g -n 10 'dig +short example.com' && echo "DNS answer changed"
According to the manual, only changes in the visible part of the screen count. - -e (
--errexit): freeze the screen when the command fails. Our test showedcommand exit with a non-zero status, press a key to exit, and after a key press watch exited with status 8. - -q N (
--equexit): exit when the output has not changed for N updates, for example when a copy has finished growing. It exists in procps-ng 4.x (Ubuntu 24.04 and 26.04, Debian 13, AlmaLinux 10) but not in AlmaLinux 9’s 3.3.17. - -b (
--beep): beep when the command returns a non-zero exit status.
Other options: -t hides the header line, -p tries to start the command at exact intervals, -c shows ANSI colours, -w turns off line wrapping and, in procps-ng 4.x, -r stops watch from re-running the command when you resize the window.
Practical examples
- Free disk space while a backup runs:
watch -n 10 df -h / - Size of a file that is being copied or downloaded:
watch -n 1 'ls -lh /root/backup.tar.gz' - Number of open TCP connections:
watch -n 2 'ss -tn state established | wc -l'(more in watch TCP and UDP ports in real time) - Busiest processes:
watch -n 2 'ps aux --sort=-%cpu | head -n 6', or usetopas in how to list running processes - Memory, uptime and load:
watch -n 5 'free -m; uptime'
To follow a log file line by line, tail -f is a better fit than watch.
Repeat a command without watch: Bash loops
watch takes over the screen. When you want each result kept on its own line, or the repeat inside a script, combine a loop with sleep:
for i in {1..3}; do echo "Run $i: $(date +%T)"; sleep 5; done
Output from our test:
Run 1: 13:36:22 Run 2: 13:36:27 Run 3: 13:36:32
To repeat forever, until you press Ctrl+C:
while true; do date +%T; sleep 2; done
To repeat until something is true, such as a file appearing:
until [ -f /tmp/ready ]; do echo "waiting..."; sleep 2; done; echo "ready"
A loop waits for the command to finish before it sleeps, so a command that takes 3 seconds plus sleep 5 repeats every 8 seconds. The sleep command guide covers minutes, hours and fractions.
Keep it running after you log out
Start the loop with nohup and &, writing to a file, then stop it later with kill and the process ID that the shell prints:
nohup bash -c 'while true; do date +%T >> /tmp/ticks.log; sleep 2; done' >/dev/null 2>&1 &
In our test the log gained a line every 2 seconds. To keep an interactive watch screen alive after you disconnect, run it inside tmux or screen.
Every 30 seconds, also after a reboot: a systemd timer
For a permanent job that runs more often than once a minute, use a systemd timer instead of cron. Create /etc/systemd/system/disk-check.service:
[Unit] Description=Log disk usage [Service] Type=oneshot ExecStart=/bin/sh -c 'df -h / >> /var/log/disk-check.log'
and /etc/systemd/system/disk-check.timer with the same name:
[Unit] Description=Run disk-check every 30 seconds [Timer] OnBootSec=30s OnUnitActiveSec=30s AccuracySec=1s [Install] WantedBy=timers.target
Then enable it and check the next run:
sudo systemctl daemon-reload sudo systemctl enable --now disk-check.timer systemctl list-timers disk-check.timer
According to the systemd manual, AccuracySec defaults to 1 minute, which is why it is set to 1 second here. systemd-analyze verify accepted both files on Ubuntu 26.04; our container had no running systemd, so we checked the files but did not start the timer. For fixed clock times use OnCalendar=*:*:0/30 instead; systemd-analyze calendar '*:*:0/30' showed the next runs at :00 and :30 of each minute.
For jobs that run once a minute or less often, cron is simpler: see how to add jobs to cron and how to read crontab syntax.