STDINから指定されたバイト数を読み取る必要があるCGIを作成したいと思います。私の考えは次のとおりです。
dd bs=$CONTENT_LENGTH count=1
しかし、ブロックサイズがRAM以外のものによって制限されるかどうかを知りたいです。
$ dd bs=1000000000000
dd: memory exhausted by input buffer of size 1000000000000 bytes (931 GiB)
GNU coreutils のマニュアルページに制限はありません。
答え1
POSIX仕様dd
最大値を明示的に指定しないでください。しかし、いくつかの制限があります。
- 指定された値を格納するために使用されるデータ型は、次のようになると予想されます。
size_t
これは、読み取るバイト数の型であるためです。read
機能; read
制限も決まっています。SSIZE_MAX
;- Linuxでは、
read
最大2,147,479,552バイトのみ転送できます。それでも。
64ビットプラットフォームでは、size_t
長さは64ビットです。また、符号がないため、2 64dd
- 1より大きい値を指定すると失敗します。
$ dd if=/dev/zero of=/dev/null bs=18446744073709551616
dd: invalid number: ‘18446744073709551616’
64ビットx86 Linuxでは、入力制限であるSSIZE_MAX
0x7ffffffffffffffffffL(実行して確認)です。echo SSIZE_MAX | gcc -include limits.h -E -
$ dd if=/dev/zero of=/dev/null bs=9223372036854775808
dd: invalid number: ‘9223372036854775808’: Value too large for defined data type
$ dd if=/dev/zero of=/dev/null bs=9223372036854775807
dd: memory exhausted by input buffer of size 9223372036854775807 bytes (8.0 EiB)
許容値が見つかった場合、次の制限は割り当て可能なメモリ量です。dd
バッファを読み込む前にバッファを割り当てる必要があるからです。
割り当て可能な値が見つかると、read
限界に達します(Linuxや同様の制限がある他のシステムの場合)。GNUを使用dd
して指定しない限りiflag=fullblock
:
$ dd if=/dev/zero of=ddtest bs=4294967296 count=1
0+1 records in
0+1 records out
2147479552 bytes (2.1 GB, 2.0 GiB) copied, 38.3037 s, 56.1 MB/s
(231dd
バイト未満のコピー、つまり上記のLinuxの制限は、私が必要とするものの半分にもなりません。
上記のQ&Aで説明されているように、fullblock
1より大きい値については、いかなる場合でもすべての入力データを確実にコピーする必要があります。bs
答え2
最大値が何であれ、POSIX仕様には大きな問題があります。
この
dd
ユーティリティは、可能な変換のために、指定された入力および出力ブロックサイズを使用して、指定された入力ファイルを指定された出力ファイルにコピーする必要があります。指定された入力チャンクサイズを使用して、一度に1つずつ入力チャンクを読み取る必要があります。その後、実際に返されたデータチャンクを処理する必要があります。要求されたブロックサイズより小さい場合があります。
(強調追加)
私が以前に書いたようにはdd
非常に愚かなツールです。あなたの場合は、本質的に次のように要約されます。
char *buf = malloc(bs);
for(int i = 0; i < count; ++i) {
int len = read(STDIN_FILENO, buf, bs);
if(len == 0) break;
write(STDOUT_FILENO, buf, len);
}
free(buf);
bs
システムコールdd
を実行するために使用される引数にすぎませんが、「短い読み取り」の実行を許可します。つまり、要求されたバイト数より少ないバイトを返します。実際に要求されたすべてでなくても、現在利用可能なバイトがある場合はこれを行います。これは、入力ファイルがtty、パイプ、またはソケットである場合(したがって、特にCGIが危険な場合)、一般的な場合です。 ..).あなたは試してください:read(2)
read(2)
$ dd bs=1000 count=1
asd
asd
0+1 records in
0+1 records out
4 bytes copied, 1.75356 s, 0.0 kB/s
ここに入力asd
してEnterキーを押します。dd
読みます(一度実行しread(STDIN_FILENO, buf, 1000)
て作成します。read
要求どおりに1回実行するため終了します。1000バイトをコピーしたようには見えません)。
最終的に単純な「標準」は、ほとんどの要件を満たすにはあまりにもdd
愚かなツールです。次のいずれかの方法で必要な操作を実行できます。
- バイト数を使用すると、
bs=1
必要なcount
バイト数のコピーが保証されますが(EOF以前に利用可能な場合)、バイトごとに1つのシステムコールを実行するため、非効率的です。 - フラグが追加されました
fullblock
。これにより、dd
書き込み前に入力ブロック全体が蓄積されます。しかし、これは非標準です(GNU ddにはあり、他にはIDKがあります)。
最終的にPOSIX以外の拡張機能を使用したい場合は、単に使用するようアドバイスがありますhead -c
。合理的なバッファリングで正しいタスクを実行し、特定のサイズ制限がなく、精度と優れたパフォーマンスを保証します。
答え3
最大値は、システム(割り当てポリシーを含む)と現在使用可能なメモリによって異なります。
あなたはそれを使用することができますdd
。
このバイトを読み取り、ファイルに保存しようとしているとします。 Bashでは、次のように実行できます($ totalの合計バイト)。
block=65535
count=$(expr $total / $block)
rest=$(expr $total % $block)
(dd bs=$block count=$count;dd bs=$rest count=1) > filename