218

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]?

2

8 Answers 8

349
watch 'command | othertool | yet-another-tool'
6
  • 6
    Might be worth noting the generic approach as well watch sh -c 'command | etc' particularly looking at the approaches tried in the question.
    – sourcejedi
    Commented Oct 25, 2016 at 18:08
  • 1
    @sourcejedi I haven't really figured out why, but this won't always produce the same results. Commented Oct 16, 2018 at 1:25
  • 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
    Commented Aug 20, 2021 at 14:14
  • 1
    Startlingly, watch injects "sh -c" normally, to run any command
    – rogerdpack
    Commented Oct 15, 2021 at 17:24
  • 1
    use -x option to use /bin/bash -c instead of sh -c for things like redirection operators command2 < <(command1) Commented Aug 2, 2023 at 16:49
23
watch -n 1 "ls -lrt | tail -n20; date"

let's you pipe and run in a row.

2
  • 1
    what is -n 1 for?
    – Nam G VU
    Commented Mar 8, 2019 at 4:50
  • 9
    @NamGVU: Run the command every 1 second
    – Duc Tran
    Commented Mar 13, 2019 at 18:46
9

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.'"
0
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 {} \; '
4

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

ls -lrt | tail -n20; date
watch "!!"
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" ")'
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.

2
  • Neither watch -x 'ls -ltr | tail -n 10' nor watch -x ls -ltr | tail -n 10 work! Commented Nov 15, 2020 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
    Commented Nov 16, 2020 at 11:21
0

With a very complex command, with mixed single- and double- quotes, it may be better to save the command as a script, and execute that.

Create myCommand.sh

vi myCommand.sh

Content:

#!/bin/bash
# My long command to watch
date; echo "Log files (some in progress):  $(ls -1 */*log | wc -l)"; echo "Current Results: "; grep -h -Po "Log entry: Command 'contains single quotes in string.*" */*log | sort | uniq -c

Make executable

chmod a+x myCommand.sh

The execute it with watch

watch -n 30 ./myCommand.sh
2
  • 1
    Of course, if you have a list of commands (especially if they total more than 80 characters), a script file is much more manageable if you put them on separate lines. Commented Dec 13, 2023 at 18:14
  • @G-ManSays'ReinstateMonica' You're not wrong! Commented Dec 14, 2023 at 19:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .