在bash中处理一行分隔数字

时间:2013-03-21 19:02:07

标签: bash numbers delimited

我有一行数字,我希望能够逐个处理它们。对于前者

3829 4837 3729 2874 3827 

我希望能够获得总和,最大数量,任何东西。但我不知道如何让每个数字来处理它。我会REAAAAALLLLLLLLLLY喜欢坚持使用纯粹的bash,我不介意在bash中使用复杂的解决方案。但如果awk绝对必要,我会用它。我不想使用sed。

我想我可以这样做:

max= cut -d" " -f1
in line L cut -d" " -f$(loop index) 
#check for max

我很困惑。

编辑: 感谢您的回答,我看到了一些我从未在bash中看到的新事物,我已经准备好更多地探索它们了。我收到了我寻求的信息甚至更多! :)

3 个答案:

答案 0 :(得分:2)

如果要逐个处理进程号,请利用 shell分词

numbers="3829 4837 3729 2874 3827"
 for n in $numbers; do
     # do something with "$n"
done

SUM

numbers="3829 4837 3729 2874 3827"
for n in $numbers; do
     ((sum+=n))
done

echo $sum

LARGEST

numbers="3829 4837 3729 2874 3827"
for n in $numbers; do
     ((max<n)) && max=$n
done

echo $max

或者,如果你想要一个带有一些shell技巧的全局SUM

$ tr ' ' '+' <<< '3829 4837 3729 2874 3827' | bc                                 
19096 

$ awk '{$1=$1; print}' OFS=+ <<< '3829 4837 3729 2874 3827' | bc
19096

$ echo  '3829 4837 3729 2874 3827' |
    awk '{for (i=1; i<=NF; i++) c+=$i} {print c}'
19096

答案 1 :(得分:2)

如果你有一个字符串中的数字列表,按照以下方式处理它们是最安全的分割和迭代方法(同时避免全局扩展或其他副作用):

max=0
read -r -a number_array <<<"$numbers"
for number in "${number_array[@]}"; do
  if (( number > max )) ; then
    max=number
  fi
done    

如果您正在阅读文件,则应用一个简单的修改(有关阅读文件的最佳做法,请参阅http://mywiki.wooledge.org/BashFAQ/001):

max=0
while read -r -a numbers; do
  for number in "${numbers[@]}"; do
    if (( number > max )) ; then
      max=number
    fi
  done
done <input-file

如果您的分隔符是其他内容,则可以适当地设置IFS。例如,如果用逗号分隔:

while IFS=, read -r -a numbers; do

请注意,当您的值仅限于数字时,此处给出的最佳实践并不重要。但是,如果输入数据中有*,则只需运行

for number in $numbers; do

然后*字符串中的$numbers将替换为当前目录中的文件列表。不要那样做。

最后一点 - bash没有内置的浮点数学支持。如果您需要浮点数学,请参阅http://mywiki.wooledge.org/BashFAQ/022

答案 2 :(得分:1)

这里有两种方法可以将一串单词拆分成一个可以迭代的结构:

使用positional parameters

numbers="3829 4837 3729 2874 3827"
set -- $numbers
sum=0
for n in "$@"; do
    # do something with $n
    (( sum += n ))
done
average=$(( sum / $# ))   # integer division only

使用实际的array

numbers="3829 4837 3729 2874 3827"
nums=( $numbers )
sum=0
for n in "${nums[@]}"; do
    # do something with $n
    (( sum += n ))
done
average=$(( sum / ${#nums[@]} ))   # integer division only