ddのbsパラメータの最大値はいくらですか?

ddのbsパラメータの最大値はいくらですか?

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最大値を明示的に指定しないでください。しかし、いくつかの制限があります。

64ビットプラットフォームでは、size_t長さは64ビットです。また、符号がないため、2 64dd - 1より大きい値を指定すると失敗します。

$ dd if=/dev/zero of=/dev/null bs=18446744073709551616
dd: invalid number: ‘18446744073709551616’

64ビットx86 Linuxでは、入力制限であるSSIZE_MAX0x7ffffffffffffffffffL(実行して確認)です。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で説明されているように、fullblock1より大きい値については、いかなる場合でもすべての入力データを確実にコピーする必要があります。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

関連情報