3

I want to define a function, and call that function every n seconds. As an example:

function h
    echo hello
end

Calling h works:

david@f5 ~> h
hello

But when using watch, it doesn't...

watch -n 60 "h"

...and I get:

Every 60.0s: h                                      f5: Wed Oct 10 21:04:15 2018

sh: 1: h: not found

How can I run watch in fish, with the function I've just defined?

0

4 Answers 4

6

Another way would be to save the function, then ask watch to invoke fish:

bash$ fish
fish$ function h
    echo hello
end
fish$ funcsave h
fish-or-bash$ watch -n 60 "fish -c h"

funcsave saves the named function definition into a file in the path ~/.config/fish/functions/, so ~/.config/fish/function/h.fish in the above case.

1
  • Much easier than the other solution, but still complicated. Perhaps I'll just reimplement watch within fish........
    – user258532
    Commented Oct 10, 2018 at 20:24
3

There is no easy way. By default watch uses /bin/sh to run commands but takes -x:

   -x, --exec
          Pass  command  to  exec(2)  instead  of  sh -c which reduces           
          the need to use extra quoting to get the desired effect.

However, nothing will not work with fish because h function is not exported to environment:

$ watch -n 5 --exec  fish -c h
Every 5.0s: fish -c h                                                                                                                                                                 comp: Wed Oct 10 21:30:14 2018

fish: Unknown command 'h'
fish:
h
^

In bash you could export a function to environment with export -f and use it inside watch like this:

$ h1 () {
> echo hi
> }
$ type h1
h1 is a function
h1 ()
{
    echo hi
}
$ export -f h1
$ watch -n 60 bash -c h1
Every 60.0s: bash -c h1                                                                                                                                                               comp: Wed Oct 10 21:29:22 2018

hi

If you use fish you can create a wrapper script and call it with watch:

$ cat stuff.sh
#!/usr/bin/env fish

function h
    date
end

h

$ watch -n5 ./stuff.sh

Also note that fish has . and source so you can define function in another file and be able to re-use it in other scripts like that:

$ cat function
function h
    echo hi
end
$ cat call.sh
#!/usr/bin/env fish

. function

h
$ watch ./call.sh
1
  • I like the solution with the wrapper script best... but yet the best solution is when everything would work within fish. I can hack a function in fish and then use watch on that function within fish.
    – user258532
    Commented Oct 10, 2018 at 20:26
0

Yes, I did it! It does the job, but I still wish fish had something native. I choose the name blotch so it doesn't interfere with bash's watch.

function blotch
    # 2018-10-10
    # 
    # This is like the watch command of bash,
    # but re-implemented in fish.
    # 
    # It takes two arguments:
    #   n: the interval in seconds
    #   fun: a fish function
    # 
    # Therefore, it is always used as:
    # 
    #   blotch n fun
    # 
    # Take note that you should start fish with
    # 
    #   sudo fish
    #   
    # before doing anything with blotch that
    # requires administrator privileges.

    set time (string split " " -- $argv)[1]
    set command (string split " " -- $argv)[2]
    while true
        sleep $time
        eval $command
    end
end

And save the function for later use.

funcsave blotch
1
  • 1
    that's a pretty ugly way to parse the arguments. I would use function blotch -a time command to instruct the command to assign the first 2 args to the "time" and "command" local variables. Then the function body can just contain the while loop. Commented Feb 19, 2019 at 16:22
0

Another quite easy way would be...

function fonzie
    echo "This is Fonzie!"
end

while true
    fonzie
    sleep 10
end

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .