1

如果我从文件中取出前 1,000 个字节,Bash 可以很快替换一些字符

$ cut -b-1000 get_video_info
muted=0&status=ok&length_seconds=24&endscreen_module=http%3A%2F%2Fs.ytimg.com%2F
yts%2Fswfbin%2Fendscreen-vfl4_CAIR.swf&plid=AATWGZfL-Ysy64Mp&sendtmp=1&view_coun
t=3587&author=hye+jeong+Jeong&pltype=contentugc&threed_layout=1&storyboard_spec=
http%3A%2F%2Fi1.ytimg.com%2Fsb%2FLHelEIJVxiE%2Fstoryboard3_L%24L%2F%24N.jpg%7C48
%2327%23100%2310%2310%230%23default%23cTWfBXjxZMDvzL5cyCgHdDJ3s_A%7C80%2345%2324
%2310%2310%231000%23M%24M%23m1lhUvkKk6sTnuyKXnPBojTIqeM%7C160%2390%2324%235%235%
231000%23M%24M%23r-fWFZpjrP1oq2uq_Y_1im4iu2I%7C320%23180%2324%233%233%231000%23M
%24M%23uGg7bth0q6XSYb8odKLRqkNe7ao&approx_threed_layout=1&allow_embed=1&allow_ra
tings=1&url_encoded_fmt_stream_map=fallback_host%3Dtc.v11.cache2.c.youtube.com%2
6quality%3Dhd1080%26sig%3D610EACBDE06623717B1DC2265696B473C47BD28F.98097DEC78411
95A074D6D6EBFF8B277F9C071AE%26url%3Dhttp%253A%252F%252Fr9---sn-q4f7dney.c.youtub
e.com%252Fvideoplayback%253Fms%253Dau%2526ratebypass%253Dyes%2526ipbits%253D8%25
26key%253Dyt1%2526ip%253D99.109.97.214%2

$ read aa < <(cut -b-1000 get_video_info)

$ time set "${aa//%/\x}"

real    0m0.025s
user    0m0.031s
sys     0m0.000s

但是,如果我占用 10,000 个字节,它会显着减慢

$ read aa < <(cut -b-10000 get_video_info)

$ time set "${aa//%/\x}"

real    0m8.125s
user    0m8.127s
sys     0m0.000s

我阅读了Greg Wooledge 的帖子,但没有解释为什么 Bash 参数扩展缓慢。

4

2 回答 2

11

至于为什么pat_subst,你可以在subst.cbash 源代码中看到这段代码的实现。

对于字符串中的每个匹配项,字符串的长度都会被计算多次(在pat_substmatch_patternmatch_upattern),既作为 C 字符串,也作为多字节字符串更昂贵。这使得函数比必要的慢,更重要的是,复杂度呈二次方。

这就是为什么较大的输入速度很慢,这是一个漂亮的图表:

shell 替换中的二次运行时

至于解决方法,只需使用sed. 它更有可能针对字符串替换操作进行优化(尽管您应该知道 POSIX 仅保证每行 8192 个字节,即使 GNU sed 处理任意大的字节)。

于 2013-02-19T23:02:04.547 回答
1

最初,由于这种原因,较旧的 shell 和其他实用程序对文件输入施加 LINE_MAX = 2048。对于巨大的变量,bash 将它们停在内存中没有问题。但是替换需要至少两个并发副本。还有很多颠簸:当字符组被删除时,整个字符串都会被重写。一遍一遍又一遍。

有一些工具适用于此 - sed 是首选。bash 是一个遥远的第二选择。sed 适用于流,bash 适用于内存块。

另一种选择:bash 是可扩展的——当 bash 不打算这样做时,您可以编写自定义 C 代码来很好地填充东西。

CFA Johnson 有关于如何做到这一点的好文章:

一些准备加载内置函数:

http://cfajohnson.com/shell/bash/loadables/

DIY内置解释:

http://cfajohnson.com/shell/articles/dynamically-loadable/

于 2013-02-19T22:42:46.640 回答