shell脚本求和_shell命令对整数求和,每⾏⼀个?
我正在寻⼀个命令,它将接受输⼊多⾏⽂本,每⾏包含⼀个整数,并输出这些整数的和。
作为⼀点背景,我有⼀个包含计时测量的⽇志⽂件,因此通过对相关⾏进⾏grepping,以及⼀点sed重新格式化,我可以列出该⽂件中的所有计时。不过,我想算出总数,我的脑⼦⾥⼀⽚空⽩,我可以把这个中间输出连接到任何命令上,以完成最后的求和。我过去⼀直使⽤expr,但除⾮它以rpn模式运⾏,否则我认为它⽆法应付这种情况(即使这样也很棘⼿)。
我错过了什么?考虑到可能有⼏种⽅法可以实现这⼀点,我很乐意阅读(并赞成)任何有效的⽅法,即使其他⼈已经发布了完成这项⼯作的不同解决⽅案。
相关问题:在Unix上计算输出列总和的最短命令?(安德鲁的学分)
更新:哇,正如预期的,这⾥有⼀些不错的答案。看来,作为⼀个通⽤的命令⾏⼯具,我⼀定要对awk进⾏更深⼊的检查!
这和我刚才问的⼀个问题⾮常相似:stackoverflow/questions/295781/…
我真的很喜欢这个问题,因为有很多可能的正确(或⾄少有效)答案。
这个问题对于代码⾼尔夫来说是个问题。codegolf.stackexchange:)
⼀点锥⼦应该做吗?
awk '{s+=$1} END {print s}' mydatafile
注意:如果要添加超过2^31(2147483647)的内容,⼀些版本的awk会有⼀些奇怪的⾏为。有关更多背景信息,请参见注释。⼀个建议是使⽤printf,⽽不是print:
awk '{s+=$1} END {printf"%.0f", s}' mydatafile
这个房间⾥有很多疯狂的爱!我喜欢这样⼀个简单的脚本如何被修改,仅仅通过将$1更改为$2就可以添加第⼆列数据。
锥⼦的极限是什么?也就是说,在死亡之前它能处理多少数据元素?或者成为使⽤⼩C代码⽚段的不太可取的⽅法?
没有实际限制,因为它将把输⼊作为流处理。所以,如果它能处理⼀个x⾏的⽂件,你可以很确定它能处理x+1。
我曾经写过⼀个基本的邮件列表处理程序,它有⼀个awk脚本,通过vaisage实⽤程序运⾏。好时光。:)
只是在a:count所有⽂档的页⾯中使⽤了这个脚本:EDOCX1[2]
是的,我要说的是你也可以把数据传输到awk…cat file.csv | cut -d, -f3 | awk '{s+=$1} END {print s}'
如何修改此项以使⽤浮动,例如包含123456.789之类数字的⾏?当你在会计系统中翻阅⼀⼤堆⽂件时,这段代码⾮常有⽤。
awk使⽤双精度浮点数,所以它应该可以正常⼯作。⽆论浮动是否适合会计核算,我都会让你来判断:)
对于像我这样不了解awk的⼈……查看此链接以获得超级快速介绍
awk断纸,适⽤于⼤量纸(注:Paste+BC继续⼯作)。
⼩⼼,它不能与⼤于2147483647(即2^31)的数字⼀起使⽤,这是因为awk使⽤32位有符号整数表⽰。⽤awk '{s+=$1} END {printf"%.0f", s}' mydatafile代替。
正如@giancarlosportelli所说,下⾯的解决⽅案更好——打印时不存在整数溢出,请参阅stackoverflow/a/25245025/992887
我想如果你有什么问题要问"我⼀直在寻⼀个执⾏x的shell命令,但我不到⼀个"。你或任何⼈应该得到的第⼀个回答是"你试过了吗?"
哈哈,我⽤锥⼦来提取这个有趣的数字。现在我看到Chrome实际上总共使⽤了⼏乎2GB的内存:)
@我只想加2美分。您可以在64位系统上使⽤"%ld"将数字保持为64位int,根本不需要转换。echo"2147483647
2147483647
2147483647
2147483647" | awk '{s+=$1} END {printf("%ld
", s)}'
与其他答案不同的是,即使数据中有空⾏,这个答案也能⼯作。
看看这个-在最后⼀个变量被打印出来之前,怎么"打印"⼀些东西呢?总共$I S
如果其中有不包含数字的⾏,会发⽣什么?如何过滤它们?
请注意,awk不知道整数是什么。它的所有数学运算都是双精度的。因此,只有达到2^53的所有数字才可表⽰。从那⼀点开始,它就错了:awk 'BEGIN{print 2^53-1, 2^53, 2^53+1}' => 9007199254740991 9007199254740992 9007199254740992。
粘贴通常合并多个⽂件的⾏,但也可⽤于将⽂件的单个⾏转换为单个⾏。分隔符标志允许您将x+x类型的公式传递给bc。
paste -s -d+ infile | bc
或者,当从stdin进⾏管道连接时,
| paste -s -d+ - | bc
很不错的!我本来会在"+"前⾯放⼀个空格,只是为了帮助我更好地解析它,但这对于通过粘贴和BC来传递⼀些内存号⾮常⽅便。
使⽤BC或DC的解决⽅案正是我所寻的解决类似问题的⽅法。我不太了解它,⽽且它似乎还未被充分利⽤,所以很⾼兴看到别⼈知道如何使⽤它。我怀疑它⽐其他解决⽅案快得多,尤其是在输⼊中有很多⾏的情况下。shell最简单脚本
⽐awk解决⽅案更容易记住和输⼊。另外,请注意,paste可以使⽤破折号-作为⽂件名,这样您就可以将命令输出中的数字通过管道传输到Paste的标准输出中,⽽⽆需先创建⽂件:| paste -sd+ - | bc。
我发现这个解决⽅案⽐使⽤⼀种成熟的编程语⾔(如awk/perl/python)要简单得多。夸奖!
令⼈惊叹的!只是⽤这个来总结所有核⼼的bogomips:cat/proc/cpuinfo grep bogo cut-d:-f2 paste-sd+bc
我有⼀份有1亿个数字的档案。awk命令需要21秒;paste命令需要41秒。但是很好地满⾜了"paste"的要求!
@阿⼘希:有趣的是:我想我要花20分钟才能弄清楚awk命令,这样它就均匀了,直到我尝试1亿和1个数字:d
@艾⽐:看看答案。在我的机器上,awk出现了⼤量故障,但paste和bc⼯作。
@乔治,你可以把埃多克斯⼀号(12号)排除在外。(如果您想将⽂件与stdin结合在⼀起,这很有⽤)。
这不喜欢⽂件中的"^m"字符,但⼀旦修复,快乐快乐快乐。
@在管道中使⽤时,不能遗漏-。echo -e"1
2
3" | paste -sd+不起作⽤,但额外的-起作⽤。
@markkcowan bc使⽤任意精度,我猜awk可能使⽤32或64位算术,可能导致溢出。
@因果关系,那么它可能是版本相关的;它在这⾥与gnu coreutils 8.24(fedora 23)⼀起⼯作;您在最后⼀个注释中的代码⽣成1+2+3。
请注意,有些shell中不包括bc,⽐如⽤于Windows的git bash。
@10basetom这是因为bc不是shell内置的(所以它不包括在任何shell中),⽽是⼀个单独的程序(在任何un*x机器上都是相当标准的)
@UML&覜ute我知道为什么它不包含在某些shell中——我指出了这⼀点,这样⼈们就可以考虑其他解决⽅案,如果他们的⽬标是可移植性的话。
有没有安装BC的问题,最后⽤echo $(( $( | paste -s -d+ -) ))来评估答案
@乔治和@abhi…因此,awk解决⽅案更容易记住…更快。双赢。
python中的⼀⾏程序版本:
$ python -c"import sys; print(sum(int(l) for l in sys.stdin))"
上⾯的⼀⾏程序不适⽤于sys.argv[]中的⽂件,但它适⽤于stackoverflow/questions/450799/…
是的-作者说他将把另⼀个脚本的输出通过管道传输到命令中,我试图尽可能缩短它的长度:)
较短的版本是python -c"import sys; print(sum(map(int, sys.stdin)))"。
我喜欢这个答案,因为它易于阅读和灵活。我需要⼀组⽬录中⼩于10MB的⽂件的平均⼤⼩,并将其修改为:find . -name '*.epub' -exec stat -c %s '{}' \; | python -c"import sys; nums = [int(n) for n in sys.stdin if int(n) < 10000000];
print(sum(nums)/len(nums))"。
⾮常灵活的解决⽅案。也可⽤于浮点数,只需将int替换为float
如果在:import sys; print(sum(int(''.join(c for c in l if c.isdigit())) for l in sys.stdin))中混合了⼀些⽂本,也可以过滤掉⾮数字。
我将对普遍认可的解决⽅案提出⼀个重⼤警告:
awk '{s+=$1} END {print s}' mydatafile # DO NOT USE THIS!!
这是因为在这种形式中,awk使⽤32位有符号整数表⽰:对于超过2147483647(即2^31)的和,它将溢出。
更⼀般的答案(对于整数求和)是:
awk '{s+=$1} END {printf"%.0f
", s}' mydatafile # USE THIS INSTEAD
另外,我本想对第⼀个答案发表评论,但我没有⾜够的声誉。
为什么printf()在这⾥有帮助?int的溢出将在此之前发⽣,因为求和代码是相同的。
因为问题实际上是在"print"函数中。awk使⽤64位整数,但出于某种原因,print不将其定为32位。
打印错误似乎已被修复,⾄少对于awk 4.0.1&bash 4.3.11是这样,除⾮我弄错了:echo -e"2147483647
100" |awk '{s+=$1}END{print s}'显⽰2147483747。
使⽤浮动只会带来⼀个新问题:echo 999999999999999999 | awk '{s+=$1} END {printf"%.0f
", s}'产⽣1000000000000000000。
平原狂欢:
$
1
2
3
4
5
6
7
8
9
10
$ sum=0; while read num; do ((sum += num)); done < ; echo $sum
55
⼀个较⼩的⼀⾏程序:stackoverflow/questions/450799/&hellip;
@Rjack,num在哪⾥定义?我相信它与< 的表达有某种联系,但不清楚是如何联系的。
@在while表达式中,它是read num的东西。
dc -f infile -e '[+z1
注意,以减号为前缀的负数应该翻译为dc,因为它使⽤_前缀,⽽不是-前缀。例如,通过tr '-' '_' | dc -f- -e '...'。编辑:因为这个答案得到了很多选票,所以下⾯是⼀个详细的解释:
表达式[+z1执⾏以下操作:
[ interpret everything to the next ] as a string
+ push two values off the stack, add them and push the result
z push the current stack depth
1 push one
is smaller
] end of the string, will push the whole thing to the stack
sr pop a value (the string above) and store it in register r
z push the current stack depth again
1 push 1
is smaller
p print the current top-of-stack
作为伪代码:
将"添加栈顶"定义为:
从堆栈中移除两个顶部值并将结果添加回
如果堆栈有两个或多个值,则递归运⾏"添加堆栈的顶部"
如果堆栈有两个或多个值,请运⾏"添加堆栈的顶部"
打印结果,现在是堆栈中唯⼀剩下的项
为了真正理解dc的简单性和强⼤性,这⾥有⼀个可⼯作的python脚本,它实现了dc中的⼀些命令,并执⾏了上述命令的python版本:
### Implement some commands from dc
registers = {'r': None}
stack = []
def add():
stack.append(stack.pop() + stack.pop())
def z():
stack.append(len(stack))
def less(reg):
if stack.pop() < stack.pop():
registers[reg]()
def store(reg):
registers[reg] = stack.pop()
def p():
print stack[-1]
### Python version of the dc command above
# The equivalent to -f: read a file and push every line to the stack
import fileinput
for line in fileinput.input():
stack.append(int(line.strip()))
def cmd():
add()
z()
stack.append(1)
less('r')
stack.append(cmd)
store('r')
z()
stack.append(1)
less('r')
p()
DC只是选择使⽤的⼯具。但我会⽤更少的堆栈操作来完成。假设所有⾏确实包含⼀个数字:(echo"0"; sed 's/$/ +/' inp; echo 'pq')|dc。
在线算法:dc -e '0 0 [+?z1。所以在处理之前,我们不保存堆栈上的所有数字,⽽是逐个读取和处理它们(更精确地说,逐⾏,因为⼀⾏可以包含多个数字)。注意,空⾏可以终⽌输⼊序列。
@伊克拉⽐,太好了。实际上,它可以再缩短⼀个字符:可以删除sed替换中的空格,因为dc不关⼼
参数和运算符之间的空格。(echo"0"; sed 's/$/+/' inputFile; echo 'pq')|dc
使⽤JQ:
seq 10 | jq -s 'add' # 'add' is equivalent to 'reduce .[] as $item (0; . + $item)'
我喜欢这个,因为我想它是如此的清晰和简短,我可能真的能够记住它。
纯粹⽽短暂的狂欢。
f=$()
echo $(( ${f//$'
'/+} ))
这是最好的解决⽅案,因为如果⽤f=$(替换第⼀⾏,它不会创建任何⼦进程。
有没有办法从stdin获得输⼊?就像从管⼦⾥?
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论