我知道使用tail -c +N
,但它非常慢,并且固定了一个 CPU 核心:
leijurvs-MacBook-Pro:Downloads leijurv$ time cat /dev/zero | head -c 100000000 | shasum -a 256
a993f8c574e0fea8c1cdcbcd9408d9e2e107ee6e4d120edcfa11decd53fa0cae -
cat /dev/zero 0.00s user 0.02s system 4% cpu 0.471 total
head -c 100000000 0.01s user 0.03s system 9% cpu 0.470 total
shasum -a 256 0.45s user 0.02s system 99% cpu 0.469 total
leijurvs-MacBook-Pro:Downloads leijurv$ time cat /dev/zero | head -c 100000000 | tail -c +2 | shasum -a 256
f4be792b71a024a60d77b3ac4c1c2b88ac51480fa25f88d10865827f8c086506 -
cat /dev/zero 0.01s user 0.03s system 0% cpu 7.241 total
head -c 100000000 0.02s user 0.03s system 0% cpu 7.240 total
tail -c +2 7.20s user 0.03s system 99% cpu 7.247 total
shasum -a 256 0.51s user 0.04s system 7% cpu 7.247 total
leijurvs-MacBook-Pro:Downloads leijurv$
head
很好。我使用 shasum 获取前 100 MB 的零head
:需要 0.47 秒。
我过去常常tail -c +2
跳过第一个字节,突然需要 7.2 秒。
tail
在此期间固定一个CPU核心。
我怎么能够表现地跳过流的前 N 个字节?
答案1
如果您只想在输入之前跳过文件的第一个字节shasum
,您可以这样做(此处使用zsh
语法,因为time
输出格式表明这就是您正在使用的 shell):
time cat /dev/zero | head -c 100000000 |
(LC_ALL=C read -u0 -k1 && shasum -a 256)
然后,这意味着没有额外的过程,第一个字节只是从管道中读取read
在开始之前shasum
。
那LC_ALL=C read -u0 -k1
是read
ing1
字符(k
此处用于钥匙最初read -k
是从终端读取按键),这里的字符是单字节LC_ALL=C
,这要归功于文件描述符u
nit 编号0
(stdin;这里为了明确我们是从流读取而不是从终端读取)。
有了bash
外壳,相当于read
命令是LC_ALL=C IFS= read -rd '' -n1
.
zsh 的等价物read -k
通常是read -N
,但这对于包含 NUL 字节的输入不起作用,它bash
只是read
条带(另外-N
,从 ksh93 复制的是一个相对较新的添加,在 macos 上找到的古老版本的 bash 中不可用)。通过将d
elimiter 设置为 NUL 字节(此处表示为空字符串),我们可以避免这种情况。是从第一个 NUL 分隔记录中-n1
读取一个字符(再次通过 生成字节)。LC_ALL=C
然而,这意味着它不能像 一样适应不同数量的字节-rd '' -n2
,如果第一个字节为 0,我们只会跳过一个字节。
对于其他 shell,您可以将该read
命令替换为dd bs=1 count=1 > /dev/null 2>&1
(change count
,不要bs
跳过超过一个字节)。head -c 1 > /dev/null
也将与一些那些head
支持非标准-c
选项的实现,但不是全部(特别是,不是 FreeBSD 的,所以可能也不是 macOS 的),因为有些实现会以固定大小的块读取输入,即使请求输出更少的字节也是如此。但请注意,与上述相反read
,当它们无法读取该一个字节时,它们不会报告失败退出状态,因此shasum
在任何情况下都会运行。
当校验和是常规文件而不是管道时,您可以执行以下操作跳绳更有效(假设需要跳过多个字节)寻求在文件中,而不是读取并丢弃要跳过的部分(仍然zsh
语法):
zmodload zsh/system
{ sysseek 1234567 && shasum -a 256; } < some-big-file
跳过前 1234567 个字节。
或者使用 ksh93:
shasum -a 256 < some-big-file <#((1234567))
与其他贝壳和一些dd
(我不知道 macOS 的实现),你可以这样做:
{ dd bs=1 skip=1234567 count=0 2> /dev/null; shasum -a 256; } < some-big-file
然而使用count=0
并不便携。当计数为 0 时,并非所有dd
实现都会执行此处的操作。有些甚至会将其理解为。lseek()
count=infinity
答案2
Mac OSXtail
速度很慢。
brew install coreutils
然后切换来gtail
解决问题。
leijurvs-MacBook-Pro:~ leijurv$ time cat /dev/zero | head -c 100000000 | tail -c +2 | shasum -a 256
f4be792b71a024a60d77b3ac4c1c2b88ac51480fa25f88d10865827f8c086506 -
cat /dev/zero 0.01s user 0.03s system 0% cpu 7.153 total
head -c 100000000 0.02s user 0.03s system 0% cpu 7.152 total
tail -c +2 7.07s user 0.03s system 99% cpu 7.159 total
shasum -a 256 0.51s user 0.06s system 7% cpu 7.154 total
leijurvs-MacBook-Pro:~ leijurv$ time cat /dev/zero | head -c 100000000 | gtail -c +2 | shasum -a 256
f4be792b71a024a60d77b3ac4c1c2b88ac51480fa25f88d10865827f8c086506 -
cat /dev/zero 0.00s user 0.02s system 4% cpu 0.497 total
head -c 100000000 0.02s user 0.08s system 18% cpu 0.496 total
gtail -c +2 0.05s user 0.10s system 30% cpu 0.496 total
shasum -a 256 0.47s user 0.02s system 99% cpu 0.496 total
leijurvs-MacBook-Pro:~ leijurv$