198

I usually use watch Linux utility to watch the output of a command repeatedly every n seconds, like in watch df -h /some_volume/.

But I seem not to be able to use watch with a piped series of command like:

$ watch ls -ltr|tail -n 1

If I do that, watch is really watching ls -ltr and the output is being passed to tail -n 1 which doesn't output anything.

If I try this:

$ watch (ls -ltr|tail -n 1)

I get

$ watch: syntax error near unexpected token `ls'

And any of the following fails some reason or another:

$ watch <(ls -ltr|tail -n 1)

$ watch < <(ls -ltr|tail -n 1)

$ watch $(ls -ltr|tail -n 1)

$ watch `ls -ltr|tail -n 1)`

And finally if do this:

$ watch echo $(ls -ltr|tail -n 1)

I see no change in the output at the given interval because the command inside $() is run just once and the resulting output string is always printed ("watched") as a literal.

So, how do I make the watch command work with a piped chain of commands [other that putting them inside a script]?

Tulains Córdova
  • 2,926
  • 4
  • 18
  • 26

7 Answers7

321
watch 'command | othertool | yet-another-tool'
DopeGhoti
  • 73,792
  • 8
  • 97
  • 133
  • 5
    Might be worth noting the generic approach as well `watch sh -c 'command | etc'` particularly looking at the approaches tried in the question. – sourcejedi Oct 25 '16 at 18:08
  • 1
    @sourcejedi I haven't really figured out why, but this won't always produce the same results. – Michael Mior Oct 16 '18 at 01:25
  • An example is `ps aux | grep something` and `watch 'ps aux | grep something'`, they are not producing the same output. – Zitrax Aug 20 '21 at 12:50
  • 1
    If you are curious about that, open it as a new question. For bonus points, include the differing output that you are seeing in the question. – DopeGhoti Aug 20 '21 at 14:14
  • 1
    Startlingly, watch injects "sh -c" normally, to run any command – rogerdpack Oct 15 '21 at 17:24
  • 1
    use `-x` option to use `/bin/bash -c` instead of `sh -c` for things like redirection operators `command2 < <(command1)` – Michael Anderson Aug 02 '23 at 16:49
22
watch -n 1 "ls -lrt | tail -n20; date"

let's you pipe and run in a row.

Soft Dot IE
  • 321
  • 1
  • 3
8

Use a combination of single quotes (') and double quotes ("). For example:

watch -n 1 "links -dump 127.0.0.1/server-status | grep -e '\S' -Fe 'www.'"
Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
Dimitar Velev
  • 81
  • 1
  • 1
4

If you would like to list all files in subdirectories too, you can use find command with exec option.

watch will update every 30 seconds and find will search for all *.log files in current dir (subdirs included) and will print filenames and their last 10 line:

watch -n30 'find . -name "*.log" -print -exec tail -n10 {} \; '
yoyomanYo
  • 41
  • 2
4

Let's say that you run a command and then want to watch it; use:

ls -lrt | tail -n20; date
watch "!!"
Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
JuanitoMint
  • 141
  • 3
3

I have just made a little bit more complex pipe chain for watching ElasticSearch nodes' performance. It requires handling variables as well as variable escaping. Hope it may be helpful to others.

watch -dn1 'kubectl exec elasticsearch-master-0 -c elasticsearch -- \
  curl -s XGET "localhost:9200/_cat/nodes?h=hp,hc,hm,rp,r,rm,cpu,dup,du,dt,m,n&v" |
  (read -r; printf "%s\n" "$REPLY"; awk "{print \$NF,\$0}" |
  sort | cut -f2- -d" ")'
Tiger peng
  • 141
  • 1
2

The simplest way is using inbuilt option -x,

watch -n 5 -x tail -4 output.log  
watch -n 2 -x ls

The first eg. will display the last 4 lines of output.log file every 5 sec., second eg list content every 2 sec.

amo
  • 37
  • 2
  • Neither `watch -x 'ls -ltr | tail -n 10'` nor `watch -x ls -ltr | tail -n 10` work! – John Lawrence Aspden Nov 15 '20 at 10:30
  • Maybe you are right. `-x` can be useful to execute something instead of `sh -c`. For your purpose you can just go with `watch 'ls -ltr | tail -n 10'` – amo Nov 16 '20 at 11:21