开发者

Problem with function arguments and for loop in bash

Why doesn't this print all the passed arguments, in bash?

function abc() {
    echo "$1" #prints the correct argument

    for x in `seq 1 $#`; do
        echo "$x" #doesn't print the 1s开发者_StackOverflow中文版t, 2nd, etc arguments, but instead 1, 2, ..
    done
}

It is printing

1
2
3
4
...

instead.


I'll just add a couple more options to what everyone else has given. The closest to the way you're trying to write this is to use bash indirect expansion:

function abc() {
    for x in `seq 1 $#`; do
        echo "${!x}"    # the ! adds a level of indirection
    done
}

...another option if you want to operate on only some of the arguments, is to use array slicing with $@:

function def() {
    for arg in "${@:2:3}"; do  # arguments 2 through 4 (i.e. 3 args starting at number 2)
        echo "$arg"
    done
}

similarly, "${@:2}" will give you all arguments starting at number 2, "${@:$start:$((end-start+1))}" will give you arguments $start through $end (the $(( expression calculates how many arguments there are between $start and $end), etc...


Actually there is a special short-hand for this case:

function abc() {
  for arg ; do
    echo "$arg"
  done
}

That is, if the in ... part is omitted, arg loops over the function's argument $@.

Incidentally if you have for arg ; ... outside of a function, it will iterate over the arguments given on the command line.


The seq command returns all numbers from start to stop. What you are calling here is seq 1 <number_of_arguments_to_abc>. For example, if you call abc alpha beta gamma, then the arguments would be seq 1 3, thus you get the numbers 1, 2 and 3.

If you want the arguments to abc instead, the expression is for x in "$@".


If you want to print all arguments try this

function abc() {
   for arg in $@; do
      echo "$arg"
   done
}


The variable X holds the literal numbers. You're trying to do indirection - substitute $1 where there's a $x. Indirection warps the brain. $@ provides a simpler mechanism for looping over the arguments - without any adverse effects on your psyche.

for x in "$@"; do
  echo $x
done

See the bash man page for more details on $@.


You should use the for arg form that others have shown. However, to address some things in your question and comments, see the following:

In Bash, it's not necessary to use seq. You can use C-style for loops:

for ((i = 2; i <= $#; i++))
do
    echo "${@:i:1}"
done

Which demonstrates array slicing which is another technique you can use in addition to direct iteration (for arg) or using shift.

An advantage of using either version of for is that the argument array is left intact, while shift modifies it. Also, with the C-style form with array slicing, you could skip any arguments you like. This is usually not done to the extent shown below, because it would rely on the arguments following a strict pattern.

for ((i = 2; i < $# - 2; i+=2))

That bit of craziness would start at the second argument, process every other one and stop before the last two or three (depending on whether $# is odd or even).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜