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).
精彩评论