60

I am not a Linux guy but stuck in some Script which I have to read for my Project. So can anyone can help me what this command is doing?

shift $(($optind - 1))
2
  • 4
    As noted below, OPTIND must be in upper case and the '$' inside the parenthesis is optional.
    – user14755
    Commented Jul 6, 2015 at 23:08
  • 1
    Simplest explanation: stackoverflow.com/a/26295865/140872
    – paradroid
    Commented Jun 21, 2021 at 22:05

2 Answers 2

80

shift $((OPTIND-1)) (note OPTIND is upper case) is normally found immediately after a getopts while loop. $OPTIND is the number of options found by getopts.

As pauljohn32 mentions in the comments, strictly speaking, OPTIND gives the position of the next command line argument.

From the GNU Bash Reference Manual:

getopts optstring name [args]

getopts is used by shell scripts to parse positional parameters. optstring contains the option characters to be recognized; if a character is followed by a colon, the option is expected to have an argument, which should be separated from it by whitespace. The colon (‘:’) and question mark (‘?’) may not be used as option characters. Each time it is invoked, getopts places the next option in the shell variable name, initializing name if it does not exist, and the index of the next argument to be processed into the variable OPTIND. OPTIND is initialized to 1 each time the shell or a shell script is invoked. When an option requires an argument, getopts places that argument into the variable OPTARG. The shell does not reset OPTIND automatically; it must be manually reset between multiple calls to getopts within the same shell invocation if a new set of parameters is to be used.

When the end of options is encountered, getopts exits with a return value greater than zero. OPTIND is set to the index of the first non-option argument, and name is set to ‘?’.

getopts normally parses the positional parameters, but if more arguments are given in args, getopts parses those instead.

shift n
removes n strings from the positional parameters list. Thus shift $((OPTIND-1)) removes all the options that have been parsed by getopts from the parameters list, and so after that point, $1 will refer to the first non-option argument passed to the script.

Update

As mikeserv mentions in the comment, shift $((OPTIND-1)) can be unsafe. To prevent unwanted word-splitting etc, all parameter expansions should be double-quoted. So the safe form for the command is

shift "$((OPTIND-1))"

7
  • It seems like this will only work right if options all occur prior to any remaining positional arguments. Correct? Commented Jul 29, 2016 at 20:16
  • @SteveJorgensen: Yes, that's correct. OTOH, putting options after non-option arguments goes against sh / bash convention. Generally, the first arguments that doesn't begin with a dash signifies the end of the options, and any subsequent args that begin with a dash are not considered to be options. Not all programs adhere to this convention, but it makes life a lot simpler if you do. :)
    – PM 2Ring
    Commented Jul 30, 2016 at 7:03
  • @SteveJorgensen: (cont) This topic is discussed briefly in Why do some utilities parse operands before options?. As Gilles' comment to Celada's answer mentions, some programs (like find) might look like they permit options after non-options, but they don't: they have operands that begin with a dash.
    – PM 2Ring
    Commented Jul 30, 2016 at 7:15
  • 1
    @roaima if IFS=0123456789, shift $((OPTIND-1)) (without quotes) will turn into shift "" which will be silently ignored (in ksh) or generate an error (in bash and dash).
    – user313992
    Commented Jul 4, 2019 at 13:01
  • 2
    It's the sort of IFS that an attacker might inject into the shell environment if they're trying to break stuff. I mean, arguably if they can modify your script's parent environment you're kinda hosed anyway, but good shells scripts try to be resilient in the face of unexpected external changes.
    – Mark Reed
    Commented Nov 9, 2020 at 17:33
17

$((...)) just calculates stuff. In your case it takes the value of $optint and substracts 1.

shift removes positional parameters. In your case it removes optint-1 parameters.

For more information have a look at help getopts, help shift, look at man bash for "Arithmetic Expansion", and especially google for getopts.

0

You must log in to answer this question.

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