ksh93怎麼這麼快?
所以,一般來說,我傾向於尋找
sed
文本處理——尤其是對於大文件——並且通常避免在 shell 本身中做這些事情。不過,我認為這可能會改變。我正在四處尋找
man ksh
,我注意到了這一點:<#pattern Seeks forward to the beginning of the next line containing pattern. <##pattern The same as <# except that the por‐ tion of the file that is skipped is copied to standard output.
對現實世界的實用性持懷疑態度,我決定嘗試一下。我做了:
seq -s'foo bar ' 1000000 >file
…對於一百萬行數據,如下所示:
1foo bar ... 999999foo bar 1000000
…並與之對抗
sed
:p='^[^0-8]99999.*bar' for c in "sed '/$p/q'" "ksh -c ':<##@(~(E)$p)'" do </tmp/file eval "time ( $c )" done | wc -l
所以這兩個命令都應該達到999999foo bar並且它們的模式匹配實現必須至少評估每行的開頭和結尾才能這樣做。他們還必須針對否定模式驗證第一個字元。這是一件簡單的事情,但是……結果不是我所期望的:
( sed '/^[^0-8]99999.*bar/q' ) \ 0.40s user 0.01s system 99% cpu 0.419 total ( ksh -c ':<##@(~(E)^[^0-8]99999.*bar)' ) \ 0.02s user 0.01s system 91% cpu 0.033 total 1999997
ksh
這裡使用 ERE 和sed
BRE。我之前用和 shell 模式做了同樣的事情,ksh
但結果並沒有什麼不同。無論如何,這是一個相當大的差異 -
ksh
超過sed
10 倍。我之前讀過 David Korn 編寫了他自己的 io lib 並在其中實現了它ksh
——這可能是相關的嗎?- 但我對此幾乎一無所知。shell 是如何做到這一點的?對我來說更令人驚訝的是,它
ksh
確實在你要求的地方留下了它的偏移量。要從*(GNU)中獲得**(幾乎)*相同的效果,您必須使用-very slow。sed``-u
這是一個
grep
訴ksh
測試:1000000 #grep + head ( grep -qm1 '^[^0-8]99999.*bar'; head -n1; ) \ 0.02s user 0.00s system 90% cpu 0.026 total 999999foo bar #ksh + head ( ksh -c ':<#@(~(E)^[^0-8]99999.*bar)'; head -n1; ) \ 0.02s user 0.00s system 73% cpu 0.023 total
ksh
在這裡節拍grep
- 但並不總是 - 他們幾乎並列。儘管如此,這還是非常棒的,並且ksh
提供了前瞻 -head
的輸入在匹配之前開始。我想,這似乎好得令人難以置信。這些命令在幕後有什麼不同?
哦,顯然這裡甚至沒有子shell:
ksh -c 'printf %.5s "${<file;}"'
ksh 不僅使用sfio,而且使用自己的自定義記憶體分配器。
儘管如此,我的猜測是 sfio 在這種情況下有所作為。我只是嘗試在 strace 下執行您的範例,可以看到 ksh 呼叫讀/寫約 200 次(65 KB 塊),而 sed 呼叫約 3400 次(4 KB 塊)。使用 sed -u 我的筆記型電腦幾乎融化了,讀取按字節完成,按行寫入。Ksh simple 使用 lseek。Grep 使用讀取約 400 次(32 KB 塊)。