Shell命令对整数求和,每行一个?
我正在寻找一个命令,它将接受(作为输入)多行文本,每行包含一个整数,并输出这些整数的总和 作为一个背景,我有一个日志文件,其中包括计时测量。通过对相关行进行grepping和一点Shell命令对整数求和,每行一个?,shell,Shell,我正在寻找一个命令,它将接受(作为输入)多行文本,每行包含一个整数,并输出这些整数的总和 作为一个背景,我有一个日志文件,其中包括计时测量。通过对相关行进行grepping和一点sed重新格式化,我可以列出该文件中的所有计时。我想算出总数。我可以通过管道将这个中间输出传输到任何命令,以便进行最终的求和。我过去一直使用expr,但除非它在RPN模式下运行,否则我认为它无法解决这个问题(即使这样也会很棘手) 如何获得整数的总和?perl-lne'$x+=$\ux;结束{print$x;}'
sed
重新格式化,我可以列出该文件中的所有计时。我想算出总数。我可以通过管道将这个中间输出传输到任何命令,以便进行最终的求和。我过去一直使用expr
,但除非它在RPN模式下运行,否则我认为它无法解决这个问题(即使这样也会很棘手)
如何获得整数的总和?perl-lne'$x+=$\ux;结束{print$x;}'perl -lne '$x += $_; END { print $x; }' < infile.txt
一点awk就可以了
awk '{s+=$1} END {print s}' mydatafile
注意:如果要添加任何超过2^31(2147483647)的内容,awk的某些版本会有一些奇怪的行为。有关更多背景信息,请参阅评论。一个建议是使用printf
而不是print
:
awk '{s+=$1} END {printf "%.0f", s}' mydatafile
如果您觉得舒服,可以使用python进行: 未测试,仅键入:
out = open("filename").read();
lines = out.split('\n')
ints = map(int, lines)
s = sum(ints)
print s
塞巴斯蒂安指出了一个单行脚本:
cat filename | python -c"from fileinput import input; print sum(map(int, input()))"
在bash中可以执行以下操作:
I=0
for N in `cat numbers.txt`
do
I=`expr $I + $N`
done
echo $I
Python中的一行程序版本:
$ python -c "import sys; print(sum(int(l) for l in sys.stdin))"
BASH解决方案,如果您希望将其作为命令(例如,如果您需要经常这样做): 然后使用:
addnums < /tmp/nums
addnums
普通bash:
$ cat numbers.txt
1
2
3
4
5
6
7
8
9
10
$ sum=0; while read num; do ((sum += num)); done < numbers.txt; echo $sum
55
$cat numbers.txt
1.
2.
3.
4.
5.
6.
7.
8.
9
10
$sum=0;同时读取num;do((sum+=num));done
以下各项应该有效(假设您的号码是每行的第二个字段)
您可以使用num-utils,尽管这对于您所需要的可能有些过分。这是一组用于在shell中处理数字的程序,可以做一些漂亮的事情,当然包括将它们相加。这有点过时了,但它们仍然有效,如果你需要做更多的事情,它们会很有用 它的使用非常简单:
$ seq 10 | numsum
55
但是对于大的输入,内存不足
$ seq 100000000 | numsum
Terminado (killed)
“粘贴”通常会合并多个文件的行,但也可用于将文件的单个行转换为一行。分隔符标志允许您将x+x类型方程式传递给bc
paste -s -d+ infile | bc
或者,当从标准DIN连接管道时
<commands> | paste -s -d+ - | bc
|粘贴-s-d+-|bc
作为伪代码:
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执行一些命令
寄存器={'r':无}
堆栈=[]
def add():
stack.append(stack.pop()+stack.pop())
def z():
stack.append(len(stack))
无def(reg):
如果stack.pop()
我意识到这是一个老问题,但我非常喜欢这个解决方案,可以与大家分享
% cat > numbers.txt
1
2
3
4
5
^D
% cat numbers.txt | perl -lpe '$c+=$_}{$_=$c'
15
如果有兴趣,我会解释它是如何工作的
$ cat n
2
4
2
7
8
9
$cat n
2.
4.
2.
7.
8.
9
$perl-MList::Util-le'print List::Util::sum()
32
或者,您可以在命令行中键入数字:
$ perl -MList::Util -le 'print List::Util::sum(<>)'
1
3
5
^D
9
$perl-MList::Util-le'print List::Util::sum()
1.
3.
5.
^D
9
但是,这个文件会发出声音,所以在大文件上使用它不是一个好主意。看看哪一个可以避免发出咕噜声。简单地击打一个衬垫
$ cat > /tmp/test
1
2
3
4
5
^D
$ echo $(( $(cat /tmp/test | tr "\n" "+" ) 0 ))
C++(简化):
SCC项目-
SCC是shell提示中的C++片段评估器,预先对后台(“”)的可读性进行道歉,但这些工作在BASH以外的shell中,因此更易于巴氏。如果您使用一个接受它的shell,$(command…)格式比'command…'更具可读性(因此也更易于调试),因此请随意修改以保持理智
我的bashrc中有一个简单的函数,它将使用awk来计算一些简单的数学项calc(){
awk 'BEGIN{print '"$@"' }'
}
这将完成+、-、*、/、^、%、sqrt、sin、cos、括号……(更多取决于您的awk版本)。。。您甚至可以使用printf和格式化浮点输出,但这是我通常需要的全部
对于这个特定的问题,我只需对每一行进行以下操作:
calc `echo "$@"|tr " " "+"`
因此,对每行求和的代码块如下所示:
while read LINE || [ "$LINE" ]; do
calc `echo "$LINE"|tr " " "+"` #you may want to filter out some lines with a case statement here
done
如果你只想逐行求和。但是,对于数据文件中的所有数字
VARS=`<datafile`
calc `echo ${VARS// /+}`
纯bash和一行中:-) 球拍中的一个衬垫:
racket -e '(define (g) (define i (read)) (if (eof-object? i) empty (cons i (g)))) (foldr + 0 (g))' < numlist.txt
racket-e'(define(g)(define i(read))(if(eof object?i)empty(cons i(g)))(foldr+0(g))”
纯粹而简短的bash
f=$(cat numbers.txt)
echo $(( ${f//$'\n'/+} ))
C(不简化)
seq 1 10 | tcc-运行我的15美分:
$ cat file.txt | xargs | sed -e 's/\ /+/g' | bc
例如:
$ cat text
1
2
3
3
4
5
6
78
9
0
1
2
3
4
576
7
4444
$ cat text | xargs | sed -e 's/\ /+/g' | bc
5148
我的版本:
seq -5 10 | xargs printf "- - %s" | xargs | bc
我要对普遍认可的解决方案提出一个严重警告:
awk '{s+=$1} END {print s}' mydatafile # DO NOT USE THIS!!
这是因为在这种形式下,awk使用32位有符号整数表示:超过2147483647(即2^31)的和将溢出
更一般的答案(对整数求和)是:
awk '{s+=$1} END {printf "%.0f\n", s}' mydatafile # USE THIS INSTEAD
与:
可选纯Perl,可读性强,不需要包或选项:
perl -e "map {$x += $_} <> and print $x" < infile.txt
perl-e“映射{$x+=$\}并打印$x”
适合红宝石爱好者
ruby -e "puts ARGF.map(&:to_i).inject(&:+)" numbers.txt
无法避免提交此文件,这是解决此问题的最通用方法,请检查:
jot 1000000 | sed '2,$s/$/+/;$s/$/p/' | dc
它是f
f=$(cat numbers.txt)
echo $(( ${f//$'\n'/+} ))
seq 1 10 | tcc -run <(cat << EOF
#include <stdio.h>
int main(int argc, char** argv) {
int sum = 0;
int i = 0;
while(scanf("%d", &i) == 1) {
sum = sum + i;
}
printf("%d\n", sum);
return 0;
}
EOF)
$ cat file.txt | xargs | sed -e 's/\ /+/g' | bc
$ cat text
1
2
3
3
4
5
6
78
9
0
1
2
3
4
576
7
4444
$ cat text | xargs | sed -e 's/\ /+/g' | bc
5148
seq -5 10 | xargs printf "- - %s" | xargs | bc
awk '{s+=$1} END {print s}' mydatafile # DO NOT USE THIS!!
awk '{s+=$1} END {printf "%.0f\n", s}' mydatafile # USE THIS INSTEAD
seq 10 | jq -s 'add' # 'add' is equivalent to 'reduce .[] as $item (0; . + $item)'
perl -e "map {$x += $_} <> and print $x" < infile.txt
ruby -e "puts ARGF.map(&:to_i).inject(&:+)" numbers.txt
jot 1000000 | sed '2,$s/$/+/;$s/$/p/' | dc
:; seq 100000000 | python -c 'import sys; print sum(map(int, sys.stdin))'
5000000050000000
# 30s
:; seq 100000000 | python -c 'import sys; print sum(int(s) for s in sys.stdin)'
5000000050000000
# 38s
:; seq 100000000 | python3 -c 'import sys; print(sum(int(s) for s in sys.stdin))'
5000000050000000
# 27s
:; seq 100000000 | python3 -c 'import sys; print(sum(map(int, sys.stdin)))'
5000000050000000
# 22s
:; seq 100000000 | pypy -c 'import sys; print(sum(map(int, sys.stdin)))'
5000000050000000
# 11s
:; seq 100000000 | pypy -c 'import sys; print(sum(int(s) for s in sys.stdin))'
5000000050000000
# 11s
:; seq 100000000 | awk '{s+=$1} END {print s}'
5000000050000000
# 22s
:; seq 50000000 | paste -s -d+ - | bc
1250000025000000
# 17s
:; seq 50000001 100000000 | paste -s -d+ - | bc
3750000025000000
# 18s
:; seq 100000000 | perl -lne '$x += $_; END { print $x; }'
5000000050000000
# 15s
:; seq 100000000 | perl -e 'map {$x += $_} <> and print $x'
5000000050000000
# 48s
:; seq 100000000 | ruby -e "puts ARGF.map(&:to_i).inject(&:+)"
5000000050000000
# 30s
#include <stdio.h>
int main(int argc, char** argv) {
long sum = 0;
long i = 0;
while(scanf("%ld", &i) == 1) {
sum = sum + i;
}
printf("%ld\n", sum);
return 0;
}
:; seq 100000000 | ./a.out
5000000050000000
# 8s
seq 10 | datamash sum 1
55
<commands...> | datamash -W sum 1
<commands...> | tr -d '[[:blank:]]' | datamash sum 1
seq 100000000 | datamash sum 1
5.00000005e+15
seq 100000000 | datamash --format '%.0f' sum 1
5000000050000000