1

I have a script I class like so gitploy up -t 2.0.0 test_repo. I pull out the "action" up right away, then I need to be able to get the test_repo before I process the options. I don't want to lose that arguments in line, if that makes sense.. don't want to shift it away, just get it and let it be? Basically I want to get that test_repo spot before I do

while getopts "zhvdurqw:c:i:e:o:b:t:f:p:g" opt; do
  case $opt in

    #flag----------------------
    h)
      usage;
      exit 0
      ;;
    #callback------------------
    c) queue_callback "$OPTARG"
      shift $((OPTIND-1)); OPTIND=1
      ;;
### so one and so forth

section of the script. So basically I can do something like this

# i would get the first argument after the options here first so "test_repo" 
# would be a $@ or $* or something?
root_arg="test_repo"

while getopts "zhvdurqw:c:i:e:o:b:t:f:p:g" opt; do
  case $opt in

    #flag----------------------
    h)
      usage;
      exit 0
      ;;
    #callback------------------
    c) queue_callback "$OPTARG"
      echo "$root_arg was here"
      shift $((OPTIND-1)); OPTIND=1
      ;;
### so one and so forth

In a broader scope of this maybe the question I would guess is, "How to get an arg by position relative to the options?"


revisal of question:

The hope is to say something like,

  • positon of getopts output in command in var
  • call the position of getopts output +1
    • test_repo argument is located +1 after getopts output
  • do normal processing

I'm trying to not move the command for backward compatibility reasons to start with, but not really limited to that. I figured I could just write a little shim here since I know the pattern is already set to gitploy <__action> [__options] <__alias> [__remote_url].

I guess I could make everything an option and deprecate the other arguments. Not sure that is a bad way to do this but it would seem that I would have to scan in an order to look for the <__alias> (or the test_repo as presented in the example) and look for it as an option such as -a test_repo.

Even if it is not the right way to do this in the end, I would like to have an answer on if you can "read the cursor" here and determine the argument value or if is an impossible thing to do.

result of answer below

while getopts "zhvdurqw:c:i:e:o:b:t:f:p:g" opt; do
    case "$opt" in
    esac
done

index="$((OPTIND))"
GD_REPO="${!index}";
OPTIND=1

This what I ended up doing. Seems like dirty trick to fast-forward then rewind, but it works. If there is better ideas, I would still love learn them.

  • 1
    Not sure I quite understand, but the way I've always done it is to put 'shift $((OPTIND-1))' (without OPTIND=1) after the while/getopt loop. Then $@ are the args after the options, $1 is the first arg after the options, etc. – mtklr Jan 22 '16 at 18:12
  • Agreed. Do not shift until after the while loop. You're probably interfering with getopts by altering OPTIND this way – glenn jackman Jan 22 '16 at 18:15
  • So I get shift will remove it, but still then I have all the options there and the question I think still remains, how do I say "get the repo_arg" in this gitploy rm -t 2.0.2 -c test repo_arg or gitploy rm -t 2.0.2 repo_arg or gitploy rm -zvd -t 2.0.2 -c test repo_arg before looping? That is the question I'm trying to get to. I need to know that argument before I loop through the options. – jeremy.bass Jan 22 '16 at 18:21
  • @mtklr isn't $1 the first one after gitploy ? like $1 on gitploy rm -vds repo_agr would be the rm ? – jeremy.bass Jan 22 '16 at 18:23
  • @glennjackman - getopts doesn't depend on the loop - it depends on $OPTIND. The asker is doing the right thing by resetting $OPTIND to 1 - which is the only way you can be sure getopts gets reset. The only problem there is you have to make sure when you do it that you do it at an argument boundary. So if you get a string of three options in an argument like while getopts :xyz o -x -xyz -z; do echo "$o:$OPTIND"; done getopts will loop a total of 5 times for the three args. – mikeserv Jan 22 '16 at 18:24
1

Your requirements are logically contradictory. Given input like gitploy up -t 2.0.0 test_repo, you need to parse the options, and in particular notice the presence of the -t option and the fact that it takes one argument, in order to identify that the first non-option argument is test_repo.

So first parse the options normally. Then you can know what the first operand is. At that point, process the options. Store the information you need about the options in variables.

action="$1"
shift
unset t_arg
while getopts "zhvdurqw:c:i:e:o:b:t:f:p:g" opt; do
  case "$opt" in
    c) c_arg="$OPTARG";;
    …
  esac
done
shift "$((OPTIND-1))"
root_arg="$1"

if [ -n "${c_arg+1}" ]; then
  queue_callback "$OPTARG"
  echo "$root_arg was here"
fi
  • I can get what you are doing there. that can be a super fallback, but I revised the question on where I am heading and the absolution question that would stop that path way. Thank you for helping – jeremy.bass Jan 25 '16 at 21:20
  • @jeremy.bass I don't understand your “revisal”. What do you call “getopts output”? If that's the final value of OPTIND, you can't get it before it's been computed, and the way to compute it is to let the while loop run its course. – Gilles Jan 25 '16 at 21:26
  • I meant how getopts is a function that returns, I presume, an array, but maybe there is a way to say because OPTIND is the index that you can infer the location, then go from there. I'm throwing darts here honestly, but the intent is to try to read the line ahead of any processing as I need that value in almost all of those areas. I am trying to think of a better way to approach this as well, but would like to duel work on this position detection problem as well. Hope that helps clear it up. Thank you for the help – jeremy.bass Jan 25 '16 at 21:38
  • @jeremy.bass No, getopts doesn't return an array. It looks at one argument at a time, two if the first turns out to be an option requiring an argument. By the time getopts gets to -c FOO, it hasn't looked beyond FOO. If you want to read the line ahead of any processing, read the line by completing the while getopts loop, and then do the processing. And my answer shows a way to do that. Another way could be to do the loop, then reset OPTIND to 1. – Gilles Jan 25 '16 at 21:43
  • so I could just to a quick while loop, [no case just empty while] just to move the index ahead, get the repo name, then reset OPTIND to 1 and do the real while loop with the case statements? – jeremy.bass Jan 26 '16 at 2:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.