Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I want to write a "forever" function that I can run multiple commands until I manually kill it with Ctrl-C. Basically, from the zsh command line, I know I can do this, and this works fine:

$ while {} { ls ; sleep 1 }

which will repeated call ls and sleep 1, forever.

I can't figure out a syntax to turn something like that into a function. Something like:

forever() { while {} { "${@}" } }

which I want to then then call with something like:

$ forever ( ls ; sleep 1 )

It probably seems silly when while {} {<commands>} and forever {<commands>} is hardly very different. But what I really want as my end goal is a "forever-sleep" function, where I can say something like

$ forever-sleep 5 ls -l
$ forever-sleep 5 ( ls -l a ; ls -l b )

and it will sleep $1 seconds after executing the command(s) I give it, forever (until I manually kill it with Ctrl-C).

(I've tried lots of combinations and nestings of (),(()),{},[],[[]],"",'', and such, and I just can't figure out how to get both the function and the command line not to have syntax errors, parse errrors, etc.)

So,

  • Is there something similar to this "forever" idea already?
  • Is this possible in a function? (I would prefer a function I can put in my .zshrc rather than having a separate executable shell script.)
share|improve this question

1 Answer 1

up vote 1 down vote accepted

You were almost there:

forever-sleep() {
   if [[ ! $1 -gt 0 ]]; then
     print "Usage $0 [time in sec] command -parameter"
     return 2
   fi
   local time=$1
   shift 1
   while true; do
      eval "$@"
      print -- "### finished: $(date) ###############################################"
      sleep $time
   done
}

The syntax then is forever-sleep [time in sec] command -parameters, like

$ forever-sleep 2 date +%s
1373873888
1373873890
1373873892
1373873894
...

A few remarks:

  • $1 -gt 0 implements a rudimentary check, if the first parameter is numerically by evaluating $1 > 0. A negative waiting time seems not sensible.
  • I used while true; do ... done, but your while {} {...} syntax works, too.
  • shift 1 is used to discard the first argument to the function (which is saved in $time, so that later the "$@" variable can be used for convenience.
  • eval "$@" in contrast to a mere "$@" makes it possible to do some more advanced stuff like

    forever-sleep 2 'foo=$(date); echo $foo'
    

    Please notice the single quotes in the latter command!

  • The print invocation gives a visual separator -- like it or not ;)
share|improve this answer
    
Beautiful. Thank you. The eval is what I was missing. (I knew about shift, but thanks for the completeness.) –  snapshoe Jul 15 '13 at 15:13

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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