258

Inside my bash script, I would like to parse zero, one or two parameters (the script can recognize them), then forward the remaining parameters to a command invoked in the script. How can I do that?

3 Answers 3

354

Use the shift built-in command to "eat" the arguments. Then call the child process and pass it the "$@" argument to include all remaining arguments. Notice the quotes, they should be kept, since they cause the expansion of the argument list to be properly quoted.

8
  • 34
    actually "$@" is safer than $*
    – pixelbeat
    Commented Oct 8, 2009 at 13:10
  • 1
    @pixelbeat: Thanks, good catch. I edited. @Łukasz Lew: see the linked-to page in the manual. :) Basically, it handles quoting better.
    – unwind
    Commented Oct 8, 2009 at 13:18
  • 28
    $@ essentially treats each element of the array as a quoted string - they are passed along without opportunity for expansion. It also ensures that each is seen as a separate word. This explanation along with a test script demonstrating the difference is here: tldp.org/LDP/abs/html/internalvariables.html#APPREF
    – Cascabel
    Commented Oct 8, 2009 at 14:43
  • 3
    Pay attention to use quotes! Read more on why it is important them around here: stackoverflow.com/a/4824637/4575793
    – Cadoiz
    Commented Jul 13, 2019 at 15:59
  • 3
    to clarify a quesiton I had before trying this solution: "$@" does not pass the script/command name itself as a parameter, unlike sys.argv[0] in C-family language. In other words, you're good to simply call whatever command it was as cmd_inside_script "$@"
    – axolotl
    Commented Feb 3, 2022 at 21:39
65

Bash supports subsetting parameters (see Subsets and substrings), so you can choose which parameters to process/pass like this.

  1. open new file and edit it: vim r.sh:

    echo "params only 2    : ${@:2:1}"
    echo "params 2 and 3   : ${@:2:2}"
    echo "params all from 2: ${@:2:99}"
    echo "params all from 2: ${@:2}"
    
  2. run it:

    $ chmod u+x r.sh
    $ ./r.sh 1 2 3 4 5 6 7 8 9 10
    
  3. the result is:

    params only 2    : 2
    params 2 and 3   : 2 3
    params all from 2: 2 3 4 5 6 7 8 9 10
    params all from 2: 2 3 4 5 6 7 8 9 10
    
52

bash uses the shift command:

e.g. shifttest.sh:

#!/bin/bash
echo $1
shift
echo $1 $2

shifttest.sh 1 2 3 produces

1
2 3
5
  • 2
    @TamásZahola care to explain? Commented Jul 17, 2018 at 17:25
  • 4
    If you forward the arguments as $1 without quoting them as "$1", then the shell will perform word splitting, so e.g. foo bar will be forwarded as foo and bar separately. Commented Jul 17, 2018 at 17:54
  • Read more on why it is important to have the double " around here: stackoverflow.com/a/4824637/4575793
    – Cadoiz
    Commented Jul 13, 2019 at 16:00
  • 4
    My brain jumbled up a couple of letters in "shifttest" and I consequently read it as something else.
    – Alex
    Commented May 23, 2020 at 17:34
  • Doesn't this only answer half the question? How do you forward the remaining parameters? Rhetorical question: the accepted answer explains you use forward-to-me.sh "$@" Commented Jan 16 at 23:16

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