[20230922]dc命令复杂学习3.txt
1.问题提出:
–//前一段时间简单学习了dc,累加的例子:
$ cat a.txt
1111
2222
3333
4444
$ cat a.txt | dc -f – -e “[+z111110
$ dc -f a.txt -e “[+z111110
–//实际上如果累加数据量很大,这样的执行效率很低的,因为每次都要判断堆栈是否还有数据(z命令,队列越长执行效率越低)
–//实际上开始我就想,如果根据开始插入堆栈的数量生成对应的数量的字符’+’ ( 注:生成+的数量等于插入堆栈的数量-1),
–//那不是更加简单呢? 自己再做一些尝试:
2.尝试实现:
$ dc -f a.txt -e “zp”
4
$ (cat a.txt ; seq 2 $(dc -f a.txt -e “zp”| tr -d ‘r’) | xargs -IQ echo + ; echo pq ) | dc -f –
11110
–//注:我的测试在cygwin下,dc -f a.txt -e “zp”的输出结果多了1个r字符,必须删除它。
–//我上面的例子使用seq 生成对应+,如何全部使用dc实现呢?
–//先做z操作插入堆栈的数量,然后产生对应数量的+就可以了.改写如下:
$ cat a.txt | dc -f – -e “z [+ la 1 – sa la 111110
$ dc -f a.txt -e “z [+ la 1 – sa la 111110
–//简单解析,不作记录我估计以后自己都看不懂代码表示怎么:
–//z 插入当前堆栈的数量到堆栈顶部,在该例子是4.
–//[+ la 1 – sa la 1–//sa 保存堆栈顶部的值到寄存器a,同时出堆栈.这里寄存器a保存的值开始是4.
–//la 把寄存器a的内容放入堆栈,这里寄存器a=4的值放入堆栈.
–//1
–//单独解析: [+ la 1 – sa la 1–// + 对当前堆栈顶部的2个数值做一次加法运算.
–// la 把寄存器a的内容放入堆栈.
–// 1 – 把1放入堆栈.并且与前面放入寄存器a的内容放入堆栈的值做减法运算.也就是做循环.
–// sa 保存堆栈顶部的值到寄存器a,同时出堆栈.
–// la 把寄存器a的内容放入堆栈
–// 1
–//加入一个显示整个堆栈的命令f就很清楚了.
$ dc -f a.txt -e “z [ + la 1 – sa la 1 f 61P 61P 61P 61P 10P 1
4
4444
3333
2222
1111
====
1
3
7777
2222
1111
====
1
2
9999
1111
====
1
1
11110
====
11110
–//如果算法改一下,要输出对应数量的字符+,该如何操作呢?
–//+的ascii码=43 ,注:在vim下在移动到+字符下按ga,在vim的提示行显示对应ascii码值(10,16,8进制). 空格的ascii=32,换行的
–//ascii=10.
$ cat a.txt | dc -f – -e “z [43P la 1 – sa la 1+++
–//注意我的以上测试并没有改变dc插入堆栈的值.你最后加入f显示整个堆栈.
$ cat a.txt | dc -f – -e “z [43P la 1 – sa la 1+++
4444
3333
2222
1111
–//使用空格分开呢?
$ dc -f a.txt -e “z [43P 32P la 1 – sa la 1+ + +
–//这样也可以写成如下:
$ (cat a.txt ; dc -f a.txt -e “z [43P 32P la 1 – sa la 111110
3.测试执行效率:
–//测试这样改进的执行效率如何?家里没有linux的环境,使用cygwin 在windows下测试:
–//cygwin的执行效率并不是很高.
$ seq 100000 > b.txt
$ time dc -f b.txt -e “[+z15000050000
real 0m10.630s
user 0m0.000s
sys 0m0.015s
$ time dc -f b.txt -e “z [+ la 1 – sa la 15000050000
real 0m0.648s
user 0m0.000s
sys 0m0.015s
–//明显快了一大截。测试使用bc看看
$ paste -sd+ b.txt | bc -l
(standard_in) 1: Function too big.
–//拚接为1行时太长了,实际上操作bc 1行接受的行长度存在限制,看下面的测试.
$ time ((sed -e ‘s/^/s+=/g’ b.txt ; echo s ) | bc -l)
5000050000
real 0m0.658s
user 0m0.061s
sys 0m0.045s
–//两者相差不大。
–//顺便测试一行最大容纳多少字符。
$ head -2499 b.txt | paste -sd+ | bc -l
3123750
$ head -2500 b.txt | paste -sd+ | bc -l
(standard_in) 1: Function too big.
$ head -2500 b.txt | paste -sd+ | wc
1 1 11393
$ head -2499 b.txt | paste -sd+ | wc
1 1 11388
–//我估计是超出bc一行能输入的字符数量的限制。因为head -2500 b.txt | paste -sd+可以正常执行。
$ time (head -2499 b.txt | paste -sd+ | bc -l)
3123750
real 0m0.535s
user 0m0.015s
sys 0m0.030s
$ time (head -2499 b.txt | dc -f – -e “z [+ la 1 – sa la 13123750
real 0m0.355s
user 0m0.000s
sys 0m0.046s
–//还是dc略胜一筹。我估计是因为bc的执行过程中使用paste拼接的原因。
$ head -2499 b.txt | paste -sd+ > c.txt
$ echo quit >> c.txt
$ time bc -l c.txt
3123750
real 0m0.146s
user 0m0.000s
sys 0m0.000s
$ head -2499 b.txt > c.txt
$ (dc -f c.txt -e “z [43P la 1 – sa la 1> c.txt
$ time dc -f c.txt
3123750
real 0m0.192s
user 0m0.000s
sys 0m0.031s
–//在写好计算公式的情况下,两者差不多,bc也许更快一些。
4.补充说明:
–//测试看看dc 以及bc 一行能接受字符的限制的具体数值.
$ head -2499 b.txt | paste -sd+ > c.txt
$ time bc -l c.txt
3123750
quit
real 0m2.148s
user 0m0.000s
sys 0m0.000s
–//尝试修改c.txt 增加文件第一行字符数量.仅仅增加1个字符就出现如下错误。
$ time bc -l c.txt
quit
c.txt 2: Function too big.
real 0m2.140s
user 0m0.015s
sys 0m0.000s
$ wc c.txt
1 1 11389 c.txt
$ ls -l c.txt
-rw-r–r– 1 Administrator None 11389 2023-09-23 20:29:27 c.txt
–//文件是linux格式,删除最后1个字符0x0a以及插入的字符,bc的一行输入缓存是11387字符。
–//多次尝试我发现实际上情况比我前面的测试要复杂:
$ head -5 e.txt
1
1
1
1
1
–//建立一个全部是数字1的文件。
$ wc e.txt
40000 40000 80000 e.txt
–//共40000行。
$ paste -sd+ e.txt | bc -l
(standard_in) 1: Function too big.
$ head -8192 e.txt | paste -sd+ |bc -l
8192
$ head -8193 e.txt | paste -sd+ |bc -l
(standard_in) 2: Function too big.
$ head -8194 e.txt | paste -sd+ | wc
1 1 16388
–//放弃探究,有点离题了。
–//测试dc的情况:
$ head -2499 b.txt | paste -sd’ ‘ > d.txt
$ ls -l d.txt
-rw-r–r– 1 Administrator None 11388 2023-09-23 20:32:51 d.txt
$ (dc -f d.txt -e “z [43P la 1 – sa la 1> d.txt
$ time dc -f d.txt
3123750
real 0m0.181s
user 0m0.000s
sys 0m0.015s
–//增加1个字符看看,修改最后的2499 为 24991。
$ time dc -f d.txt
3146242
real 0m0.214s
user 0m0.000s
sys 0m0.015s
–//3123750 – 2499 +24991 = 3146242 , 结果正确。
$ paste -sd’ ‘ b.txt > d.txt
$ (dc -f d.txt -e “z [43P la 1 – sa la 1> d.txt
$ time dc -f d.txt
5000050000
real 0m0.461s
user 0m0.000s
sys 0m0.015s
$ ls -l d.txt
-rw-r–r– 1 Administrator None 688897 2023-09-23 20:41:58 d.txt
$ cat d.txt | dc -f –
5000050000
–//dc没有这个限制,甚至bash shell命令行的限制。
–//bash shell命令行的限制我记忆里各个版本不一致,好像最大可以达到128K,有一些甚至2621440。我不测试了。
$ getconf -a | grep -i arg
_POSIX_ARG_MAX 4096
NL_ARGMAX 9
ARG_MAX 32000
$ getconf ARG_MAX
32000
–//我的cygwin测试环境32000.