【问题标题】:Process a line of delimited numbers in bash在 bash 中处理一行分隔数字
【发布时间】:2013-03-11 11:05:11
【问题描述】:

我有一行数字,我希望能够一个一个地处理它们。例如。

3829 4837 3729 2874 3827 

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

我想我可以这样做:

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

我很困惑。

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

【问题讨论】:

  • 如果你想坚持纯bash,不要添加处理编程语言的标签=)(从标签中删除)
  • 谢谢!我仍然习惯于程序员的术语。 :)

标签: bash numbers delimited


【解决方案1】:

如果你想一一处理进程号,利用shell分词

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

SUM

numbers="3829 4837 3729 2874 3827"
echo $((${numbers// /+}))

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

【讨论】:

  • 这是一个整数列表 Charles Duffy =)
  • 当然可以,但我不打算教别人如何在他们在不同的输入域中工作时立即生成错误的做法。
【解决方案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

【讨论】:

  • 整数列表不需要while IFS=, read -r。再读一遍标题=)
  • @sputnick 取决于整数的分隔方式。如果它们用逗号分隔,IFS=, 肯定是需要的。我确实在文中指出,IFS=, 仅在这种情况下才需要; SO 的部分陈述点是拥有一个可供其他人使用的知识库,而不是只回答直接和直接的问题。
  • 还有一件事,你在哪里读到关于 OP POST 中的“文件”的东西?我只看到“线”,所以是一个字符串。
  • @sputnick 够公平的。修改为从更简单的非基于文件的答案开始。
  • 谢谢!!!我实际上是从文件中读取的,但是处理部分我在想太多时迷失了自己。也感谢数学提示!附言昨天,我从毛边源打印出了 bash 指南。我明白了,我正朝着正确的方向前进。
【解决方案3】:

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

使用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

【讨论】:

  • 谢谢!!!! $@ 是指项目列表吗?在使用 set -- $numbers 时,您是在声明 $@ = $numbers 吗?感谢您指出位置参数。我学到的东西比我预期的要多。 :)
猜你喜欢
  • 2020-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-19
  • 1970-01-01
相关资源
最近更新 更多