2

Following up on the top answer to this question, I thought I could:

1) Define a command:

cmd='for x in $(my_command | grep keyword | cut -d" " -f1); do command2 "arguments" $x; done'

2) Run it on a loop as follows

while true; do "$cmd"; sleep 1; done

However, the above doesn't work, and I get the following

zsh: command not found for x in $(......
zsh: command not found for x in $(......
zsh: command not found for x in $(......
...

Any thoughts why?

Clarification:

If I run for x in $(my_command | grep keyword | cut -d" " -f1); do command2 "arguments" $x; done' it works perfectly.

Addendum:

I have noticed that if I use eval, it works, i.e.:

while true; do eval "$cmd"; sleep 1; done

runs the command cmd every second

2 Answers2

7

If you want to prepare a command for running inside the same shell, use a function.

cmd () {
  for x in $(my_command | grep keyword | cut -d" " -f1); do
    command2 "arguments" $x
  done
}
while true; do cmd; sleep 1; done
4

By putting quotes around $cmd, you're asking the shell to run a command named exactly that. There is not command named "for x in $(..."; in fact on my system, there isn't even a command named "for" - it's a shell keyword. To run the contents of $cmd, you'll have to use eval.

Shawn J. Goff
  • 46,081
  • Thanks @Shawn. Hhmm, but why does the above syntax work for watch then? (see the link to a related question at the beginning of the OP) – Amelio Vazquez-Reina Oct 26 '11 at 22:05
  • Nevermind, I think that @Guilles explained that in the watch example "$cmd" is passsed as an argument to bash, which I guess explains why it does not need eval – Amelio Vazquez-Reina Oct 26 '11 at 22:10
  • 1
    It is because the shell is expecting a string, which it interprets line-by-line; just as it would when running a script from a file. – Shawn J. Goff Oct 26 '11 at 22:14