Part of my job involves some data handling. One of the tasks is to 'flatten' a set of directories (which we'll call Dir for now), and copy them to a new location called DirFlat.

This can take a long time (30 minutes ->2-3 hours)! I'd like to be able to watch the progress, so I use find Dir -type f|wc -l to get the number of files (lets call this $Filenum, and then I run a very short command that I wrote (retyping from my notebook, may have copied it wrong, I hope you get the gist):

echo $(echo "($ls DirFlat |wc -l)*100/$FileNum"|bc) "%" $(date)

However, if I run watch -n 100 "!!" it takes the output of the echo, and keeps printing that (even the date doesn't change).

Can I get this to refresh the variable/re-run the assignment of the internal variables in BASH? Hopefully this will help me in automating some of my tasks.

  • This really doesn't sound like the right process. There are good answers to your question here, but I think it's the wrong approach. This is a perfect opportunity to use cron. Cron will run a command regularly and then email you the output. Could you just have a script that cron runs? Something that would check if the process is running, and if it is running, email a status email? Have that run every 10 minutes or so. You only get emails when it's working. You don't have to run anything interactively. You don't tie up server resources by constantly piping data back to your terminal. – ClashTheBunny Jun 15 '17 at 13:18


$ watch -n 1 "echo $(date)"
Every 1.0s: echo Sat Apr 27 03:10:50 CEST 2013

$ watch -n 1 'echo $(date)'
Every 1.0s: echo $(date)

What you've done is to run echo "($ls DirFlat |wc -l)*100/$FileNum"|bc and date, substitute the output of each command into the shell command watch -n 100 "echo $(…) % $(…)", and run that. You need to prevent the expansion of the command in the parent shell, and instead pass it as a string to watch for it to run. This is a simple matter of using single quotes around the command instead of double quotes.


Alternatively you can wrap it into a shell loop:

while sleep 100; do
    (... your stuff ...)
    if [ (... process has finished ...) ]; then
        (... beep or get operator's attention otherwise ...)
  • This is probably the behaviour I'm after! If I push this to the background, will it still output to the terminal? – Pureferret Apr 26 '13 at 12:53
  • 1
    Yes, but remember not to close the terminal. Or better run it in a terminal multiplexer like tmux or screen. – peterph Apr 26 '13 at 18:46

You have to put this into a shell script and let watch call this script then.

  • Could you give me an example? – Pureferret Apr 26 '13 at 10:22
  • @Pureferret Example? watch -n 100 /my/script.sh? – Hauke Laging Apr 26 '13 at 10:27

A while loop with the command you want to run and the sleep command will also allow you to run the linux command repeatedly like the watch command. Although, in this specific case @peterph's answer is better since it has a terminating condition. This shorter response only answers the question on how to refresh when re-running the same process.

while true; do echo $(date +"%T"); sleep 1; done

The number after sleep is in seconds.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.