0

tl;dr summary: In Bash, what is the best way to handle multiple command line arguments with varying positions depending on user input?

I have a script with multiple case statements to handle multiple arguments. However, the position of each argument may vary depending on user input. I have something like this:

case $1 in 
-a) 
    this lists all package tracking info
    ;;
-u)
    this lists only the most recent update
    ;;
-d)
    this runs -u in a loop of intervals of n (secs, mins, or hours)
    ;;
...
esac

case $2 in
-f)
    this parses $file (default or user-defined)
    ;;
    ...
esac

The tricky part here is that when the user passes the argument -d, they have the additional option of specifying a time interval for daemon() to run it's loop, such as -d 2h. I also want to give the user the ability to specify a file to parse (the -f flag). When the user specifies -d -f, there's no problem, but when they specify a time and a file, -d 2h -f file.txt, then $2 = 2h and$3 = -f causing -f to get interpreted as something else (a package tracking number) later on in the script.

So, I tried to use a conditional in between case statements 1 and 2 to change the $2 in the 2nd case statement. Something like:

if [[ "$2" =~ ^.[h,m,s] ]];
     then
         last_flag="/$3"
     else
         last_flag="/$2"
fi

case $last_flag in
-f)
    check_flag
    ;;
 esac

But, this doesn't appear to work. when I enter -d 2h -f at the command line,echo $last_flag = $3 as expected, but $last_flag isn't being substituted in the case statement. I don't think the escaped $ is the problem, either (I tried it without that as well).

  • What am I doing wrong here?
  • Is there a better way to handle multiple input arguments with varying positions in Bash?

I suppose the easiest thing would be to simply change the order of the flags, leaving -d at the end, so it doesn't matter whether the user specifies a time-interval or not. But, there are other circumstances in which input arguments would be shifted, such as if the user passes -f but doesn't supply a file name (in which case a default file is chosen). So, either way, I have to confront this problem. I suspect it will require a re-write of the general flow of the script, but perhaps not.

Sophie
  • 304
  • 10
  • 12
  • See BashFAQ #35: http://mywiki.wooledge.org/BashFAQ/035 – Charles Duffy Aug 07 '15 at 23:41
  • 1
    ...the important thing, here, is the `shift` command to consume arguments; that way, whether there were optional arguments consumed is moot. – Charles Duffy Aug 07 '15 at 23:42
  • 1
    Have you considered using `while ([ "$1" ]) ... shift; done` ? – technosaurus Aug 07 '15 at 23:43
  • @technosaurus, why the subshell? – Charles Duffy Aug 07 '15 at 23:45
  • I just found this, which I'll have to read through. Sorry for the dupe! https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash It appears that `shift` is what I want, though. I wish I knew about it before, it could have saved me a lot of wasted time :D – Sophie Aug 07 '15 at 23:45
  • If you still have questions / places where you think the duplicate flag is in error after reading through that answer and the relevant FAQ, feel free to @-reply me here (ideally after editing the question or commenting to make those still-outstanding aspects clear; editing the question will also put it into the queue for folks to vote on whether to reopen it). – Charles Duffy Aug 07 '15 at 23:48
  • No problem re: the dupe -- we actually like well-written duplicates here, if their title and keywords make them easier to find than the original was, or if they're more likely to be found by folks who are thinking of a problem from a different perspective; they serve as pointers to whichever invocation of the question ends up being canonical. Duplicate questions where there was clearly no effort are less welcome, but that's not so much the case here. – Charles Duffy Aug 07 '15 at 23:49
  • Will do. I think the duplicate flag is justified, though. Thanks for pointing me to some additional resources/already answered questions. – Sophie Aug 07 '15 at 23:52
  • 1
    For the sake of completeness (and for anyone that stumbles across this), I used technosaurus's suggestion (sans the subshell): `while [[ "$2" =~ ^.[h,m,s] ]]; do shift; done` Works perfecttyl (so far). – Sophie Aug 08 '15 at 00:16

0 Answers0