22

The problem is that when watch is executed it runs sh and I get this error:

sh: 1: func1: not found

here is the code:

#!/bin/bash

func1(){
  echo $1
}

export -f func1

watch func1
Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
Rachid O
  • 343
  • 1
  • 3
  • 9

3 Answers3

22

The default shell for watch is /bin/sh. Shells will not inherit exported variables or functions from other types of shell.

If your system does not symlink /bin/sh to /bin/bash (or your current shell) then you can instruct watch to exec your shell by using -x or --exec:

watch -x bash -c "my_func"

or

watch --exec bash -c "my_func"

This is different to watch bash -c "test_watch" (excluding the --exec) as it doesn't use /bin/sh to spawn the child process (in this case, bash), maintaining bash all the way down. As caveated in other answers, this can get messy if exporting functions that are highly coupled to the current environment (i.e. requiring other variables or functions).


An example:

test_watch() { echo 'Working!'; }
export -f test_watch
watch --exec bash -c "test_watch"

gives the familiar

Every 2.0s: bash -c test_watch                                   Thu Mar 31 11:15:56 2016

Working!
Andy
  • 403
  • 3
  • 8
11

Ok, so there are a few issues with your approach.

You are exporting a function, which is not portable between shells. watch executes its commands with /bin/sh, which on your system is not bash. And whatever shell it is, it doesn't respect function exports, so you get the error.

Secondly, you can change your command to something like watch bash -c 'func1', but this may not work well either.
The reason here being that any variables set by the script won't be available to the function. You might be able to export the ones it needs, but that starts getting messy.

The safest solution is to put func1 in a script by itself and call that script.
 

In short, try:

watch bash -c func1
phemmer
  • 70,657
  • 19
  • 188
  • 223
  • 1
    It is very CPU intensive in case function is defined in `.bash_profile` – VarunAgw Feb 01 '16 at 16:59
  • @VarunAgw, that is a good point. However, it is a great command for monitoring things in an environment where the `.bash_profile` file is relatively empty. However, I did want to run an alias that was in my `.bash_aliases` file (_sourced through my `.bashrc`_), so I ended up adding the `-i` flag to bash as well. I thought that might help someone: `watch bash -ic "func1; alias1; func2; …"` – aaiezza May 01 '17 at 13:01
  • Only `watch -x bash -c my-func` work for me on Ubuntu Server 16.04 - while others don't. – Nam G VU Mar 12 '19 at 02:26
4

Why run watch from inside your script? Why not have this shell script:

$ cat func1 
#!/bin/bash

func1(){
  echo $1
}

func1 $1

... and then run it like so ...

$ watch func1 foo
Red Cricket
  • 2,183
  • 6
  • 25
  • 37