1

I want to run a retry function that accepts as arguments an operator and a cmd in order to reuse the function.. e.g.

"-z" and "pgrep -f 'sleep 10'"
"! -z" and "pgrep -f 'sleep 10'"
#!/bin/bash

retry() {
    local -r operator="$1"; shift
    local -r cmd="$@"

    retry_count=5
    attempts=0

    echo "run $cmd"
    #until [ $operator `pgrep -f 'sleep 10'` ] <---this works
    until [ $operator `${cmd}` ]
    do
        sleep $((++attempts))
        if [ $attempts -gt $retry_count ]; then
            echo "failed. exit with error"
            exit 1
        fi
        echo "try again ..."
    done
    
    echo "success"
}

retry "! -z" "pgrep -x 'sleep 10'"
retry "-z" "pgrep sleep"

I got this error message:

pgrep: only one pattern can be provided
Try `pgrep --help' for more information.

I am open to use a different approach.

Chris
  • 315
  • 1
  • 4
  • 17
  • 3
    Quotes embedded inside variables are literal data and don't have any special properties. The typical solution is to use an array - `local -r cmd=( "$@" )` and then `[ $operator $( "${cmd[@]}" ) ]`. See also [BashFAQ/050 - I'm trying to put a command in a variable, but the complex cases always fail!](http://mywiki.wooledge.org/BashFAQ/050) – tjm3772 May 17 '23 at 13:19
  • Additionally the function call would be, for example, `retry "! -z" pgrep -x 'sleep 10'` – tjm3772 May 17 '23 at 13:21
  • @tjm3772 your approach works fine. you could provide this as the answer – Chris May 17 '23 at 13:30

1 Answers1

0

In the first retry example, the single quotes are not interpreted anymore by the shell, because this would have to be done after parameter expansion. Therefore, the command pgrep gets called with the following three parameters:

-f
'sleep
10'

This would be equivalent to run pgrep with

pgrep "-f"   "'sleep"  "10'"

which should produce the same error message.

As a solution, I suggest that you define cmd as array instead of a scalar:

cmd=("$@")

and evaluate it as

[ $operator `${cmd[@]}` ]

or better avoid the obsolete backquotes and write

[ $operator $("${cmd[@]}") ]

Of course in your case, you can get rid of the variable and simply write

[ $operator $("$@") ]
user1934428
  • 19,864
  • 7
  • 42
  • 87