ストリームの最初のNバイトを効率的にスキップします。

ストリームの最初のNバイトを効率的にスキップします。

使用することを知っているが、tail -c +N非常に遅く、1つの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を使って最初の100MBに対して0を得ましたhead。 0.47秒かかりました。

tail -c +2以前は最初のバイトをスキップしていましたが、突然7.2秒かかりました。

tailこの間、1つのCPUコアが固定されます。

どうやってできるか表現的にストリームの最初のNバイトをスキップしますか?

答え1

ファイルを入力する前にファイルの最初のバイトをスキップするにshasumzshtime

time cat /dev/zero | head -c 100000000 |
   (LC_ALL=C read -u0 -k1 && shasum -a 256)

これは追加のプロセスがなく、最初のバイトがパイプから読み取られることを意味します。read始める前にshasum

それはLC_ALL=C read -u0 -k1まさにreading1文字です(kここでは最初は、read -kキー入力が端末から読み取られます。ここでの文字は、LC_ALL=Cファイル記述子のuニット番号0(stdin;ここでは端末ではなくストリームから読み取ることを明確にするため)のおかげでシングルバイトです。

シェルを使用すると、bash次のようになります。readコマンドはですLC_ALL=C IFS= read -rd '' -n1

zshに対応するのはread -k一般的ですが、read -NNULバイトを含む入力には機能せず、bash単にreadストライピングにすぎません(また、-Nksh93からコピーしたものは比較的新しい追加エントリであり、macosの古代バージョンのbashでは使用できません)。区切り文字をNULバイト(ここでは空の文字列で示されている)に設定することでdこれを防ぐことができます。最初のNULで区切られたレコードから1文字を読み取ります-n1(再バイトを生成することによって)。LC_ALL=Cただし、これは他のバイト数に適応しないことを意味します-rd '' -n2。最初のバイトが0の場合、バイトをスキップします。

他のシェルの場合は、readコマンドをdd bs=1 count=1 > /dev/null 2>&1(change、1バイト以上スキップしないcountでください)に置き換えることができます。また、一緒に動作しますbshead -c 1 > /dev/null一部head非標準オプションをサポートしていますが、-cすべてではありませんが(特にFreeBSDではないため、おそらくmacOSではない可能性があります)、一部はより少ないバイトの出力が要求されても、固定サイズのチャンクで入力を読み取ります。ただし、上記とは異なり、対応するread1バイトを読み取ることができない場合は、失敗した終了ステータスを報告しないため、いずれにせよ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ポータブルで使用することはできません。 countが0の場合、すべてのdd実装がここで作業を実行するわけではありません。一部ではこのように解釈することもあります。lseek()count=infinity

答え2

Mac OSXはtail遅いです。

brew install coreutilsgtail次に、トラブルシューティングのために切り替えます。

 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$ 

関連情報