我的shell脚本出了什么问题?当在函数中使用循环时,总是会有一些异常

时间:2016-12-24 01:42:12

标签: linux bash shell

这是我的剧本:

#!/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

这里是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 

我的linux版本是centos 7.0,当我只在脚本中使用循环而不是函数时,进程时不会有错误

1 个答案:

答案 0 :(得分:2)

这里有许多混淆的来源。首先,每当你在反引号中使用echo somethingorother之类的东西时,你就会做一些奇怪而毫无意义的事情;它接受字符串(在我的示例中是另一个),将其转换为输出(echo命令),然后反引号捕获输出并将其转换回字符串。最终结果:echo和反引号有效地相互抵消,然后您返回原始字符串。嗯,大多数;有几件奇怪的事情可能会让事情搞得一团糟。只需跳过echo和反引号,直接使用字符串。所以,例如,这一行:

arg1=`echo ${myarray[*]}`

可以替换为

arg1=${myarray[*]}

而且BTW名称arg1与该变量包含的内容或它的使用方式(好吧,等等)不匹配。它包含所有 myarray的元素,而不仅仅是第一个元素。它似乎也意味着它的值将作为所有的参数传递给addarray(虽然发生了不同的事情,因为我会稍微解释一下)。

其次,您处理错误的数组。接受我刚才提到的命令;它接受数组的所有元素,并将它们(在它们之间有空格)组合成一个字符串,并将该字符串存储在arg1中。因此,myarray是数组("1" "2" "3" "4" "5"),但arg1只是单个字符串" 1 2 3 4 5"。

addarray函数中存在一些类似的混淆。使用以下函数将函数的参数存储为数组:

newarray=(`echo "$@"`)

(好吧,大多数情况下 - 这实际上是接受参数,小心地将每个参数传递给echo作为参数,它们将它们之间的空格粘在一起,然后将输出分成基于空格和每个单词的单词存储为newarray的元素。如果参数中有任何空格,那么这些空格现在将被拆分为单独的数组元素,这通常是一个错误。更糟糕的是,如果任何参数包含shell通配符,它​​们就是#39 ; \ n \ n会被匹配文件列表替换。这不是问题,但有时你会尝试将" *"传递给函数来告诉它繁殖,并且它最终会出现一个文件名列表并且非常困惑。正确的方法是newarray=("$@")。)

然后你引用newarray就好像它只是一个普通的字符串变量:

for value in $newarray

这只需要newarray的第一个元素(您需要${newarray[@]}${newarray[*]}来获取所有元素)。然后,由于它不是双引号,它会将其拆分为基于空格的单词,然后将任何通配符扩展为匹配文件名列表。获取数组的所有元素时,您几乎总是希望使用"${newarray[@]}"来单独处理每个元素,而不是单词分割或通配符扩展。

现在最大的问题。这一行:

result=`addarray arg1`

运行函数addarray,并将参数" arg1"传递给它。不是变量arg1,而是它的值(" 1 2 3 4 5"),只是文本字符串" arg1"。因此,在函数内部,newarray只获得一个元素," arg1&#34 ;;并且for循环运行一次,value设置为" arg1"。这意味着循环中的行:

sum=$[ $sum+$value ]

扩展为:

sum=$[ 0+arg1 ]

但由于$[ ]的内部是算术上下文,因此字符串" arg1"被隐式地视为变量名称并扩展为其内容,给出:

sum=$[ 0+1 2 3 4 5 ]

其中" 2 3 4 5"部分没有意义,给出你看到的错误。

现在让我添加一些风格注释:在声明函数时,funcname()function funcname更标准和可移植。使用$(( ))代替其过时的等效文件$[ ]。使用$( )代替反引号来捕获命令的输出 - 它更容易阅读,反引号有一些奇怪的语法后果可能会让你感到沮丧。最后,最好将变量引用放在双引号中(例如echo "$sum"而不是echo $sum),即使它不是绝对必要的。

这是更正后的版本:

#!/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"

哦,还有一个建议:shellcheck.net非常适合指出脚本中常见的错误和不良做法。在您学习的同时,通过它来运行您的脚本,它可以帮助您避免养成各种不良习惯。