61

Hi i have the following:

bash_script parm1 a b c d ..n

I want to iterate and print all the values in the command line starting from a, not from parm1

Alberto Zaccagni
  • 30,779
  • 11
  • 72
  • 106
piet
  • 805
  • 3
  • 9
  • 9
  • 1
    possible duplicate of [Remove first element from $@ in bash](http://stackoverflow.com/questions/2701400/remove-first-element-from-in-bash) – user May 01 '14 at 15:29

5 Answers5

153

You can "slice" arrays in bash; instead of using shift, you might use

for i in "${@:2}"
do
    echo "$i"
done

$@ is an array of all the command line arguments, ${@:2} is the same array less the first element. The double-quotes ensure correct whitespace handling.

James Newton
  • 6,623
  • 8
  • 49
  • 113
Ismail Badawi
  • 36,054
  • 7
  • 85
  • 97
  • 3
    Be careful, as slicing may cause problems with whitespace in e.g. globbed paths. The file `folder/my file` will be split to `folder/my` and `file` if invoked as `./script.sh folder/*`. The accepted answer using `shift` and `$1` works as intended in this case. – jkgeyti Jan 08 '15 at 09:50
  • 7
    @jkgeyti This isn't a problem with globbed paths, just a problem with whitespace handling. Properly quoting like `for i in "${@:2}"; do echo "$i"; done` fixes that issue. – Erik Feb 05 '16 at 19:25
  • Could someone edit the quotes into the answer? I'd have almost missed the comment that fixes the whitespace issue. – wrtlprnft Oct 25 '17 at 12:00
29

This should do it:

#ignore first parm1
shift

# iterate
while test ${#} -gt 0
do
  echo $1
  shift
done
Sebastian
  • 6,293
  • 6
  • 34
  • 47
Scharron
  • 17,233
  • 6
  • 44
  • 63
9

Another flavor, a bit shorter that keeps the arguments list

shift
for i in "$@"
do
  echo $i
done
Déjà vu
  • 28,223
  • 6
  • 72
  • 100
  • (You might also change `echo $i` to `echo "$i"` -- that way `./yourscript '*'` actually prints `*`, not a list of files; it also means that `./yourscript $'argument\twith\ttabs'` actually prints tabs, instead of having them changed to spaces). – Charles Duffy Sep 01 '17 at 11:53
9

This method will keep the first param, in case you want to use it later

#!/bin/bash

for ((i=2;i<=$#;i++))
do
  echo ${!i}
done

or

for i in ${*:2} #or use $@
do
  echo $i
done
ghostdog74
  • 327,991
  • 56
  • 259
  • 343
7

You can use an implicit iteration for the positional parameters:

shift
for arg
do
    something_with $arg
done

As you can see, you don't have to include "$@" in the for statement.

Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439