0

我试图创建一个 shell 脚本,对给定的数字求和。如果没有给定参数,则它会尝试读取管道输出,但出现错误。

#!/bin/sh

sum=0

if [ $# -eq 0 ]
then
  while read data
  do
    sum=`expr $sum + $data`
  done
else
  for ((  i = 1 ;  i <= $#;  i++  ))
  do
    sum=`expr $sum + ${!i}`
  done
fi

echo $sum

这有效:sum 10 12 13 但是这个无效:echo 10 12 13| sum

提前致谢,

4

1 回答 1

3

给你(假设bash,不是sh):

#!/bin/bash

sum=0

if (( $# == 0 )); then
  # Read line by line
  # But each line might consist of separate numbers to be added
  # So read each line as an array!
  while read -a data; do
    # Now data is an array... but if empty, continue
    (( ${#data[@]} )) || continue
    # Convert this array into a string s, with elements separated by a +
    printf -v s "%s+" ${data[@]}
    # Append 0 to s (observe that s ended with a +)
    s="${s}0"
    # Add these numbers to sum
    (( sum += s ))
  done
else
    # If elements come from argument line, do the same!
    printf -v s "%s+" $@
    # Append 0 to s (observe that s ended with a +)
    s="${s}0"
    # Add these numbers to obtain sum
    (( sum = s ))
fi

echo $sum

您可以这样调用它:

$ echo 10 12 13 | ./sum
35
$ ./sum 10 12 13
35
$ # With several lines and possibly empty lines:
$ { echo 10 12 13; echo; echo 42 22; } | ./sum
99

希望这可以帮助!

编辑。您可能也有兴趣了解有关IFS. 我注意到人们往往会混淆@*bash. 如果你不知道我在说什么,那么你应该使用@代替*,也用于数组下标!在bash手册中,您会发现当双引号时,$*(或${array[*]})扩展为数组的所有元素,IFS. 这在我们的例子中很有用:

#!/bin/bash

sum=0

if (( $# == 0 )); then
  # Read line by line
  # But each line might consist of separate numbers to be added
  # So read each line as an array!
  while read -a data; do
    # Now data is an array... but if empty, continue
    (( ${#data[@]} )) || continue
    # Setting IFS=+ (just for the sum) will yield exactly what I want!
    IFS=+ sum=$(( sum + ${data[*]} ))
  done
else
    # If elements come from argument line, do the same!
    # Setting IFS=+ (just for the sum) will yield exactly what I want!
    IFS=+ sum=$(( $* ))
fi

echo $sum

Gniourf 现在退出教师模式。:-)

于 2012-11-11T12:50:15.423 回答