17

I recently learned about watch, but am having trouble making it work with relatively sophisticated commands.

For example, I would like to ask watch to run the following command on zsh every three seconds*:

for x in `command_1 | grep keyword | cut -d' ' -f1`; do command_2 "word[word=number]" $x; done

as you can see the line above includes single quotes, double quotes, among other special characters.

So I tried:

watch -n 3 "for x in `my_command | grep keyword | cut -d' ' -f1`; do command2 "rusage[mem=7000]" $x; done"

but then I got:

no matches found for x in !@#$# ....; done

I tried other combinations without success. Here's one of those attempts:

watch -n 3 "for x in $(bjobs -w | grep pre_seg | cut -d' ' -f1); do bmod -R "rusage[mem=7000]" $x; done"

which also results in a similar error.

Any ideas how to make this work?


*I would also be intersted in solutions that work on bash

1 Answer 1

23

General tip: if you have two levels of nesting, avoid using single quotes in the inner command, and use single quotes around the outer command.

Additional tip: don't use backticks - `…` - to execute code, instead use $(…) around it. Dollar-parentheses is pretty much DWIM('Do what I mean') when it comes to nested quotes; backquotes have arcane, shell-dependent rules.

watch -n 3 'for x in $(my_command | grep keyword | cut -d" " -f1); do command2 "rusage[mem=7000]" "$x"; done'

If you need single quotes inside a single-quoted command, you can use '\''. Think of these four characters as the way to quote a single quote inside single quotes, though technically speaking this is constructed as end the single-quoted string, append a literal single quote, and start a new single-quoted string (still appended to the current word).

For more complex cases, either painstakingly count the quotes, or define temporary variables.

cmd='for x in $(my_command | grep keyword | cut -d" " -f1); do command2 "rusage[mem=7000]" "$x"; done'
watch_cmd='watch -n 3 "$cmd"'

This answer isn't specific to zsh. Zsh doesn't bring anything major here. You can save a bit of quoting because there's no need for double quotes around command substitutions, and sometimes there are ways to use built-ins rather than external commands which reduce the quoting needs, but the underlying issues are the same as in other shells.

Oh, and by the way, note that watch will execute your command in sh, not in zsh. If you want to execute the command in zsh, you need to run

watch -n 3 -x zsh -c "$cmd"

on Debian/Ubuntu, and

export cmd
watch -n 3 'exec zsh -c "$cmd"'

(even more quoting!) elsewhere.

5
  • Thanks @Gilles. That was very helpful. Interestingly watch does not come with the -x nor -c options on my machine. I looked it up online and haven't found any man pages that mention them. What do these options do? Commented Oct 26, 2011 at 21:45
  • 1
    @intrpc -x tells watch not to pass the command through a shell. I just found out that this is specific to Debian/Ubuntu, even though it's not indicated as such. The -c is passed to zsh, not to watch. Commented Oct 26, 2011 at 22:03
  • @Gilles The -x and -exec options both exist in my watch (on gentoo), so this is definitely not Debian-specific. Maybe you compared with some other version of watch? Mine comes from procps package. Commented Oct 27, 2011 at 6:46
  • 1
    @rozcietrzewiacz watch comes from procps on Debian too. The official source doesn't have --exec. The package in Debian (and derivatives including Ubuntu) adds the option in a Debian-specific patch (watch_exec_beep.patch; it's “Mortys watch exec patch” from bug #410967). Gentoo may have adopted a similar patch. Commented Oct 27, 2011 at 7:42
  • 1
    This was the key part for me!: "If you need single quotes inside a single-quoted command, you can use '\''. Think of these four characters as the way to quote a single quote inside single quotes, though technically speaking this is constructed as end the single-quoted string, append a literal single quote, and start a new single-quoted string (still appended to the current word)." Commented Sep 2, 2021 at 23:26

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.