this is my script:
#!/bin/bash #adding values in an array function addarray { local sum=0 local newarray newarray=(`echo "$@"`) for value in $newarray do sum=$[ $sum+$value ] done echo $sum } myarray=(1 2 3 4 5) echo "the origin array is : ${myarray[*]}" arg1=`echo ${myarray[*]}` echo $arg1 result=`addarray arg1` echo "the result is $result
here is errormessage
the origin array is : 1 2 3 4 5 1 2 3 4 5 test11: line 9: 1 2 3 4 5: syntax error in expression (error token is "2 3 4 5") the result is
My linux version is centos 7.0,and when i use loop only in script not in function,there will not be erros when process
Advertisement
Answer
There are a number of sources of confusion here. First, whenever you use anything like echo somethingorother
in backquotes, you’re doing something weird and pointless; it takes the string (somethingorother in my example), converts it to output (of the echo
command), then the backquotes capture the output and convert it back to a string. Net result: the echo
and the backquotes effectively cancel each other, and you get the original string back. Well, mostly; there are several weird things that might happen to mess things up. Just skip both echo
and backquotes, and use the string directly. So, for example, this line:
arg1=`echo ${myarray[*]}`
could be replaced by
arg1=${myarray[*]}
And BTW the name arg1 doesn’t match what this variable contains or how it’s used (well, sort of). It contains all the elements of myarray
, not just the first. It also appears you meant its value to be passed as all of the arguments to addarray
(although something different is happening, as I’ll explain in a bit).
Second, you’re handling arrays wrong. Take that command I just mentioned; it takes all the elements of the array, and sticks them together (with spaces between) into a single string, and stores that string in arg1
. Thus, myarray
was the array ("1" "2" "3" "4" "5")
, but arg1
is just the single string “1 2 3 4 5”.
There’s some similar confusion inside the addarray
function. You store the function’s arguments as an array with this:
newarray=(`echo "$@"`)
(well, mostly — this actually takes the arguments, carefully passes each on to echo
as an argument, which sticks them together with spaces between, then that output is split into words based on spaces and each word is stored as an element of newarray
. If there were any spaces within arguments, those will now be split into separate array elements, which is usually a mistake. Worse, if any of the arguments contain shell wildcards, they’ll be replaced by a list of matching files. This isn’t a problem here, but sometime you’re going to try to pass “*” to a function to tell it to multiply, and it’s going to wind up with a list of filenames and be very confused. The correct way to do this is newarray=("$@")
.)
Then you refer to newarray
as if it was just a plain string variable here:
for value in $newarray
This takes just the first element of newarray
(you’d need ${newarray[@]}
or ${newarray[*]}
to get all the elements). Then since it’s not double-quotes it splits that into words based on spaces, and then expands any wildcards into lists of matching filenames. When getting all elements of an array, you almost always want to use "${newarray[@]}"
to get each element treated separately, but not word-split or wildcard-expanded.
Now the biggest problem. This line:
result=`addarray arg1`
runs the function addarray
, and passes it the argument “arg1”. Not the variable arg1
, not its value (“1 2 3 4 5”), just the text string “arg1”. Thus, inside the function, newarray
gets just a single element, “arg1”; and the for
loop runs once, with value
set to “arg1”. That means the line inside the loop:
sum=$[ $sum+$value ]
expands to:
sum=$[ 0+arg1 ]
but since the inside of $[ ]
is an arithmetic context, the string “arg1” is implicitly treated as a variable name and expanded to its contents, giving:
sum=$[ 0+1 2 3 4 5 ]
in which the “2 3 4 5” part makes no sense, giving the error you see.
Now let me add several stylistic notes: when declaring a function, funcname()
is more standard and portable than function funcname
. Use $(( ))
instead of its obsolete equivalent, $[ ]
. Use $( )
instead of backquotes to capture the output of a command — it’s easier to read, and backquotes have some weird syntactic consequences that can trip you up. Finally, it’s best practice to put variable references in double-quotes (e.g. echo "$sum"
instead of echo $sum
), even when it’s not strictly necessary.
Here’s a corrected version:
#!/bin/bash #adding values in an array addarray() { local sum=0 local newarray newarray=("$@") # This keeps each argument a separate array element for value in "${newarray[@]}" # This iterates over the elements cleanly do sum=$(( sum+value )) # In arithmetic context, $ is not needed for variables done echo "$sum" } myarray=(1 2 3 4 5) echo "the origin array is : ${myarray[*]}" # [*] mashes the elements together with spaces between, but that's ok here result=$(addarray "${myarray[@]}") # Pass each array element as a separate argument echo "the result is $result"
Oh, and one more recommendation: shellcheck.net is great at pointing out common mistakes and bad practices in your scripts. While you’re learning, run your scripts through it, and it’ll save you from developing a variety of bad habits.