Search code examples
bashshell

What does "set -- ${@:2}" mean?


I have a shell script, and a line in that is set -- ${@:2}. What does it mean? I have tried in my test script. It seems to remove the $1 param in args. Could you help me with more details?


Solution

  • It's a complicated way of writing shift.*

    First, what is set --?

    • set has many uses. It can change shell options, for instance with set -e to enable strict error checking or set -x to print each command that's run.
    • set can also change the $1, $2, etc., command-line arguments. set foo bar baz sets $1 to "foo", $2 to "bar", and $3 to "baz".
    • -- is a common idiom that means "stop looking for flags". If you write set -e then you get error checking, but with set -- -e the -e is no longer a flag, it's now the value of $1.

    Okay, and what about"${@:2}"?

    • "$@" is the list of command-line arguments. Writing "$@" is like writing "$1" "$2" "$3" ... for however many arguments there are.
    • :2 is array slice notation. It gives you the elements of an array starting at the 2nd element. "${@:2} gives you all the command-line arguments starting with the second. It's like writing "$2" "$3" "$4" ....
    • $var is shorthand for ${var}. Curly braces are optional for simple expansions, required for more complicated ones. To use array slicing, "$@" must be written as "${@}". "$@:2" doesn't work: the shell parses it as "${@}:2".

    Put them together and you get "set the command-line arguments to $2, $3, $4, etc." Or, as you said, it gets rid of $1.

    Which is exactly what shift does.

     

    * Actually, shift is equivalent to set -- "${@:2}" with double quotes. Missing double quotes is a bug that'll bite you if any argument contains whitespace or globbing characters (*, ?, etc.). When in doubt, always quote variable expansions!