Iterate over arguments in a bash script and make use of their numbers

狂风中的少年 提交于 2020-08-27 11:37:48

问题


If I want to iterate over all arguments it is as easy as for i in "$@"; do .... However, let's say I want to start with the second argument and also make use of the arguments' positions for some basic calculation.

As an example I want to shorten these commands into one loop:

grep -v 'foobar' "$2" | grep -f $file > output1.txt
grep -v 'foobar' "$3" | grep -f $file > output2.txt
grep -v 'foobar' "$4" | grep -f $file > output3.txt
grep -v 'foobar' "$5" | grep -f $file > output4.txt

I tried many variations like for i in {2..5}; do grep -v 'foobar' "$$i" | grep -f $file > output$(($i-1)).txt; done; however, it seems bash expansion doesn't work like this.

EDIT:

Seems I made a mistake not emphasizing that I need to make use of the argument's position/number (i.e., 2 from $2). It's important because the output files get used separately later in the script. All of the provided answers so far seem correct but I don't know how to use them to make use of the argument's "number".


回答1:


If you do not want to shift off the first unneeded arguments you can use the indirection expansion:

for i in {2..5}; do
  echo "${!i}"
done



回答2:


Couple correct answers already, another way could be:

for (( i=2; i <= "$#"; i++ )); do
    echo "arg position: ${i}"
    echo "arg value: ${!i}"
done



回答3:


You can also make use of array indexes directly:

#!/bin/bash
for i in "${@:2}"; do
    echo "$i"
done

Which will iterate over the arguments beginning with the second argument. It will also preserve whitespace in arguments when quoted. e.g.

$ bash args.sh one two "three four" five
two
three four
five



回答4:


You just need to use shift to move positional parameter once (thus discarding $1):

fn() { arg1="$1"; shift; for arg; do echo "$arg"; done; }

Call it as:

fn val1 val2 val3 val4

Output:

val2
val3
val4



回答5:


Above answers are correct. Another approach:

a=("${@:2}")

for i in ${!a[@]}; do
    echo "$i = ${a[i]}"
done



回答6:


$@ is similar to an array, with the small difference that it is one-based and not zero-based ($0 is the name of the shell or shell script), and it can't be indexed (${@[1]} won't work to access $1). You can use parameter expansion (more specifically: substring expansion) to access a subset of your positional parameters:

$ set arg1 arg2 arg3 arg4 arg5   # Set $1, $2, $3, $4, $5
$ for i in "${@:2}"; do echo "$i"; done
arg2
arg3
arg4
arg5

Notice that this will not actually allow you to use the index of the argument and the argument itself. To do that, you'd have to either turn the positional parameters into a regular array and deal with the index offset by one ($1 would have index 0), or use indirect expansion (see andlrc's answer).

Example of the first method:

$ set arg1 arg2 arg3 arg4 arg5
$ args=("$@")
$ for i in 3 2 5 1 4; do echo "\$$i is ${args[$((i-1))]}"; done
$3 is arg3
$2 is arg2
$5 is arg5
$1 is arg1
$4 is arg4

Clearly, ${args[$((i-1))]} is rather messy, but it works.


Side note: if you want to access all positional parameters, you can use a convenient shorthand:

$ for i; do echo "$i"; done
arg1
arg2
arg3
arg4
arg5

for without the in part loops over all positional parameters (see manual).



来源:https://stackoverflow.com/questions/37053780/iterate-over-arguments-in-a-bash-script-and-make-use-of-their-numbers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!