【发布时间】:2012-11-18 02:06:42
【问题描述】:
我正在尝试添加由read -a 命令的用户输入定义的数组元素。我该怎么做?
【问题讨论】:
我正在尝试添加由read -a 命令的用户输入定义的数组元素。我该怎么做?
【问题讨论】:
read -a array
tot=0
for i in ${array[@]}; do
let tot+=$i
done
echo "Total: $tot"
【讨论】:
let 可以处理小数吗?我不得不使用total=$(echo "$total + $i" | bc -l)
给定一个(整数)数组,这是一种添加其元素的有趣方法(在 bash 中):
sum=$(IFS=+; echo "$((${array[*]}))")
echo "Sum=$sum"
例如,
$ array=( 1337 -13 -666 -208 -408 )
$ sum=$(IFS=+; echo "$((${array[*]}))")
$ echo "$sum"
42
Pro:没有循环,没有子shell!
缺点:仅适用于整数
随着这篇文章的火爆,我想与大家分享另一种有趣的方式,使用dc,它不仅限于整数:
$ dc <<< '[+]sa[z2!>az2!>b]sb1 2 3 4 5 6 6 5 4 3 2 1lbxp'
42
这条美妙的线将所有数字相加。整洁,嗯?
如果您的号码在数组中array:
$ array=( 1 2 3 4 5 6 6 5 4 3 2 1 )
$ dc <<< '[+]sa[z2!>az2!>b]sb'"${array[*]}lbxp"
42
事实上,负数有一个陷阱。数字'-42'应该给dc作为_42,所以:
$ array=( -1.75 -2.75 -3.75 -4.75 -5.75 -6.75 -7.75 -8.75 )
$ dc <<< '[+]sa[z2!>az2!>b]sb'"${array[*]//-/_}lbxp"
-42.00
会的。
专业版:适用于浮点数。
缺点:使用外部进程(但如果您想进行非整数运算,则别无选择 - 但dc 可能是此任务中最轻的)。
【讨论】:
$(...)) 创建了一个子shell。请参阅mklement0's answer 至 When does command substitution spawn more subshells than the same commands in isolation?。
我的代码(我实际使用的)的灵感来自gniourf_gniourf 的答案。我个人认为这更易于阅读/理解和修改。也接受浮点数,而不仅仅是整数。
对数组中的值求和:
arr=( 1 2 3 4 5 6 7 8 9 10 )
IFS='+' sum=$(echo "scale=1;${arr[*]}"|bc)
echo $sum # 55
只需稍加改动,即可得到数值的平均值:
arr=( 1 2 3 4 5 6 7 8 9 10 )
IFS='+' avg=$(echo "scale=1;(${arr[*]})/${#arr[@]}"|bc)
echo $avg # 5.5
【讨论】:
arr=( 1 2 3 4 5 6 7 8 9 10 ); echo $(IFS='+'; bc<<<"scale=1;(${arr[*]})/${#arr[@]}") 另外,您可以使用“Here String”而不是 echo 来保存 1 个进程。
gniourf_gniourf 的 answer 非常棒,因为它不需要循环或 bc。对于任何对真实示例感兴趣的人,这里有一个函数可以汇总从 /proc/cpuinfo 读取的所有 CPU 内核,而不会弄乱 IFS:
# Insert each processor core count integer into array
cpuarray=($(grep cores /proc/cpuinfo | awk '{print $4}'))
# Read from the array and replace the delimiter with "+"
# also insert 0 on the end of the array so the syntax is correct and not ending on a "+"
read <<< "${cpuarray[@]/%/+}0"
# Add the integers together and assign output to $corecount variable
corecount="$((REPLY))"
# Echo total core count
echo "Total cores: $corecount"
我还发现,当从双括号内调用数组时,算术扩展可以正常工作,无需读取命令:
cpuarray=($(grep cores /proc/cpuinfo | awk '{print $4}'))
corecount="$((${cpuarray[@]/%/+}0))"
echo "Total cores: $corecount"
通用:
array=( 1 2 3 4 5 )
sum="$((${array[@]/%/+}0))"
echo "Total: $sum"
【讨论】:
我喜欢简洁,所以这是我倾向于使用的:
IFS="+";bc<<<"${array[*]}"
它本质上只是列出数组的数据并将其传递给 BC 来评估它。 “IFS”是内部字段分离,它本质上指定如何分离数组,我们说用加号分隔它们,也就是说当我们将它传递给BC时,它会收到一个由加号分隔的数字列表,所以很自然它将它们加在一起。
【讨论】:
<<< simbol?
另一个dc & bash 方法:
arr=(1 3.88 7.1 -1)
dc -e "0 ${arr[*]/-/_} ${arr[*]/*/+} p"
输出:
10.98
上面运行表达式0 1 3.88 7.1 _1 + + + + p 和dc。注意虚拟值0,因为+s 太多了,还要注意dc 中通常的负数前缀- 必须更改为_。
【讨论】:
arr=(1 2 3) //or use `read` to fill the array
echo Sum of array elements: $(( ${arr[@]/%/ +} 0))
Sum of array elements: 6
解释:
"${arr[@]/%/ +}" 将返回 1 + 2 + 3 +
1 + 2 + 3 + 0
$(( "${arr[@]/%/ +} 0")))包装此字符串,它将改为返回总和这可以用于其他数学运算。
- 代替* 和1 而不是0
也可以与逻辑运算符一起使用。
BOOL 和示例 - 检查所有项目是否为真 (1)
arr=(1 0 1)
if [[ $((${arr[@]/%/ &} 1)) -eq 1 ]]; then echo "yes"; else echo "no"; fi
这将打印:否
BOOL 或示例 - 检查任何项目是否为真 (1)
arr=(1 0 0)
if [[ $((${arr[@]/%/ |} 0)) -eq 1 ]]; then echo "yes"; else echo "no"; fi
这将打印:是的
【讨论】:
一个简单的方法
function arraySum
{
sum=0
for i in ${a[@]};
do
sum=`expr $sum + $i`
done
echo $sum
}
a=(7 2 3 9)
echo -n "Sum is = "
arraySum ${a[@]}
【讨论】:
我发现使用递增变量非常简单:
result2=0
for i in ${lineCoffset[@]};
do
result2=$((result2+i))
done
echo $result2
【讨论】: