LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Blogs > goumba
User Name
Password

Notices


Rate this Entry

[bash] Continue to attempt running a command until it succeeds, or a specified number of tries.

Posted 08-12-2014 at 10:56 PM by goumba

Inspired by the dsc in his post, http://www.linuxquestions.org/questi...og.php?b=36164, I decided to try and get the number of tries part working, and here's what I came up with:

Code:
#!/bin/bash                                                                     
set -x # remove/comment when you no longer wish to see debugging output

case $1 in
    [0-9]*)
        max=$1
        # shift so that $@ only contains the command we're interested in        
        shift
        ;;
    *)
        max=10
        ;;
esac

command="$@" # Not necessary, I suppose, but makes the execution clearer below.
tries=0

false # The above line sets a success exit code, so we fix that here.
until [[ $? -eq 0 ]] || [[ $tries -gt $(($max-1)) ]]
do
    tries=$((tries+1))
    $command
done
Posted in bash scripting
Views 678 Comments 6
« Prev     Main     Next »
Total Comments 6

Comments

  1. Old Comment
    I read that same blog entry and had a go myself a few days ago. Was waiting for the author to respond to your comment before joining the discussion, but he didn't. Anyway, here's what I came up with, which is a similar approach to yours but slightly different
    Code:
    #!/bin/sh
    #
    # Repeatedly try to run a command until successful outcome,
    # or a max of 'n' attempts have been made.
    #
    # Usage:  tryagain [n] "<command> [arg1] ..." 
    
    isnum()
    {
      case "$1" in
        ''|*[!0-9]*)    return 1 ;;
        *)              return 0 ;;
      esac
    }
    
    runcommand()
    {
      sh -c "$@"
      rc=$?
      return $rc
    }
    
    
    if isnum "$1"; then
      n="$1"
      shift
    else 
      n=0
    fi
    
    until runcommand "$@"
    do
      [ $n -eq 1 ] && echo "Gave up trying!" >&2 && break
      [ $n -ne 0 ] && n=$(( $n - 1 ))
    done
    
    exit $rc
    n=0 means try forever in my implementation, which is different to yours.

    Putting the command to run at the bottom of the body of the until loop like you did means that unlike mine, you didn't need the function to capture the return code - I should have thought of that - but then my approach meant I didn't need to call /bin/false before entering the loop.

    Interesting to see a different approach. Thanks for posting.
    Posted 08-13-2014 at 03:51 PM by GazL GazL is offline
    Updated 08-13-2014 at 04:13 PM by GazL (Don't know what happened there, got corrupted while posting :doh:)
  2. Old Comment
    Awesome man.

    I will admit I am no shell guru, I know probably enough just to get done what I want to get done, and certainly room for improvement.

    As far as infinitely trying, I had considered it, but I tried to keep along the functionality of the original post.

    Of course, there's only one way to do it, post a piece of work and get critiques and see improvements.

    Thanks.
    Posted 08-13-2014 at 08:00 PM by goumba goumba is offline
  3. Old Comment
    Quote:
    I will admit I am no shell guru,
    Neither am I, and I'm always wary of those who claim they are!


    As for critique, your script was pretty good, but I'll offer two small things that caught my attention:

    1) Your case statement will incorrectly consider a string such as "7_is_a_prime" as a number.

    2) By using command="$@" and then later $command on its own to execute the command, you're negating the special word splitting that happens when $@ is used within quotes, so you would have been better not to use the intermediate and have used "$@" directly to execute the command.

    Try running your script like this and you'll see the impact it'll make:
    ./goumbas_script 2 ls -l "/tmp/file with spaces"

    BTW, because I used su -c "$@" in my script (an attempt to support compound commands), mine also has issues around word-splitting that need to be addressed with escapes/quoting on the command line, and as such was probably a mistake.
    Posted 08-14-2014 at 06:40 AM by GazL GazL is offline
    Updated 08-14-2014 at 06:53 AM by GazL
  4. Old Comment
    You're absolutely right, I figured by using quotes around $@ that it would be fine, but isn't necessarily the case. Admittedly, my testing apparently was not diverse enough.

    It does seem I got lazy with the number checking.

    Thanks for the input.
    Posted 08-14-2014 at 07:27 AM by goumba goumba is offline
  5. Old Comment
    Duh! I feel so stupid now. "$1" is the only thing that needs to be checked to figure out if it's a number, there's absolutely no need to do something more complex with the entire "$@", along the lines of checking if "grep ^[[:digit:]]" is positive.
    Posted 08-18-2014 at 02:15 PM by the dsc the dsc is offline
  6. Old Comment
    It seems that it's virtually impossible to make a script get a strictly literal "$@" with quotes and everything, quotes have to be escaped.

    For folders or files with spaces between quotes, though, it may be of some help to use:

    command="$(printf "%q " "$@")"

    That will escape spaces within the quotes found in $@.

    But I'm not sure it will work well for something like: tryagain wget www.site.com/filexyz.ext -O "file name with spaces.ext"
    Posted 08-18-2014 at 05:56 PM by the dsc the dsc is offline
 

  



All times are GMT -5. The time now is 08:19 PM.

Main Menu
Advertisement
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration