GNU/Linux >> Linux の 問題 >  >> Linux

Ddはいつデータのコピーに適していますか? (または、Read()とWrite()が部分的である場合)?

ショートバージョン: ddはどのような状況ですか データのコピーに安全に使用できます。安全とは、部分的な読み取りまたは書き込みによる破損のリスクがないことを意味しますか?

長いバージョン—前文: dd 特にデバイスとの間でデータをコピーするためによく使用されます(例)。他のツールよりも低いレベルでデバイスにアクセスできるという神秘的な特性が原因である場合があります(実際には、魔法を実行しているのはデバイスファイルです)が、 dd if =/ dev / sda cat / dev / sdaと同じです 。 dd 速いと思われることもありますが、 cat 実際にそれを打ち負かすことができます。それでも、 dd 独自の特性を備えているため、真に役立つ場合があります。

問題: dd if =foo of =bar 実際、 cat barと同じではありません 。ほとんどのユニス¹では、 dd read()を1回呼び出します 。 (POSIXは、 ddの「入力ブロックの読み取り」を構成するものについてあいまいだと思います。 。) read()の場合 部分的な結果を返します(POSIXおよびその他の参照ドキュメントによると、実装ドキュメントで特に明記されていない限り、これは許可されています)、部分的なブロックがコピーされます。 write()にもまったく同じ問題が存在します 。

観察 :実際には、 dd ブロックデバイスや通常のファイルに対応できますが、それは私があまり行使していないということかもしれません。パイプに関しては、 ddを配置するのは難しくありません 故障して;たとえば、次のコードを試してください:

yes | dd of=out bs=1024k count=10

outのサイズを確認します ファイル(10MBをはるかに下回る可能性があります)。

質問 :どのような状況で dd データのコピーに安全に使用できますか?つまり、ブロックサイズ、実装、ファイルタイプなどの条件によって、 ddが確実になります。 すべてのデータをコピーしますか?

(GNUDdにはfullblockがあります read()を呼び出すように指示するフラグ またはwrite() 完全なブロックを転送するためにループで。したがって、 dd iflag =fullblock 常に安全です。私の質問は、これらのフラグ(他の実装には存在しない)が使用されていない場合についてです。)

¹
OpenBSD、GNU coreutils、BusyBoxをチェックしました。

承認された回答:

仕様から:

  • bs =の場合 expr オペランドが指定されており、 sync以外の変換はありません 、 noerror 、または notrunc 要求された場合、各入力ブロックから返されるデータは、個別の出力ブロックとして書き込まれます。 read()の場合 フルブロック未満を返し、 sync 変換が指定されていない場合、結果の出力ブロックは入力ブロックと同じサイズになります。

だから、これはおそらくあなたの混乱を引き起こすものです。はい、 dd 設計 ブロッキングの場合、デフォルトでは部分的な read() sは部分的なwrite()に1:1でマッピングされます s、または sync bs =へのテールパディングNULまたはスペース文字を削除します conv =syncの場合のサイズ が指定されています。

これは、 ddを意味します データのコピーに安全に使用できます(部分的な読み取りまたは書き込みによる破損のリスクはありません) count =によって任意に制限されている場合を除くすべての場合 それ以外の場合はddであるため、引数 喜んでwrite() 入力がread()であったものと同じサイズのブロックでの出力 read()になるまで sそれを完全に通過します。そして、この警告でさえ唯一の真実 bs =の場合 指定またはobs= ではありません 仕様の次の文として指定されています:

  • bs =の場合 expr オペランドが指定されていないか、 sync以外の変換 、 noerror 、または notrunc 要求された場合、入力は処理され、フルサイズの出力ブロックに収集されます 入力の終わりに達するまで。
関連:Debian –ワイヤレス接続が繰り返し失われますか?

ibs =なし および/またはobs= 引数これは重要ではありません– ibs およびobs デフォルトでは両方とも同じサイズです。ただし、明示的になることができます 異なるサイズを指定して入力バッファリングについて どちらの場合でも bs =を指定する (優先されるため)

たとえば、次の場合:

IN| dd ibs=1| OUT

…次に、POSIX dd write() 収集による512バイトのチャンク 単独でread() バイトを単一の出力ブロックに。

それ以外の場合は…

IN| dd obs=1kx1k| OUT

…POSIXdd read() 最大 一度に512バイト、ただし write() すべてのメガバイトサイズの出力ブロック(カーネルはおそらく最後のものを許可および除外します-それはEOFであるため) フルサイズの出力ブロックに入力を収集することにより、完全に 。

ただし、仕様からも:

  • count =n
    • コピーのみn 入力ブロック。

count = i?bs =にマップします ブロックなど、 count =の任意の制限を処理するため 移植には、2つの ddが必要です s。 2つのddでそれを行う最も実用的な方法 sは、ある出力を別の入力にパイプ処理することにより、特別なファイルの読み取り/書き込みの領域に確実に配置されます。 元の入力タイプに関係なく。

IPCパイプとは、 [io] bs =を指定する場合を意味します 安全に行うには、そのような値をシステムで定義された PIPE_BUF内に保持する必要があるという引数 制限。 POSIXは、システムカーネルはアトミックな read()のみを保証する必要があると述べています sおよびwrite()PIPE_BUFの制限内 Limits.hで定義されているとおり 。 POSIXは、 PIPE_BUFを保証します 少なくとも

  • {_ POSIX_PIPE_BUF}
    • パイプへの書き込み時にアトミックであることが保証されている最大バイト数。
    • 値:512

(これはデフォルトの ddでもあります i / oブロックサイズ) 、ただし、実際の値は通常少なくとも4kです。最新のLinuxシステムでは、デフォルトで64kです。

したがって、 ddを設定するとき ブロックファクターで実行する必要があるプロセス 3つの値に基づく:

  1. bs =(obs = PIPE_BUF 以下)
  2. n=必要な合計バイト数
  3. count =n / bs

いいね:

yes | dd obs=1k | dd bs=1k count=10k of=/dev/null
10240+0 records in
10240+0 records out
10485760 bytes (10 MB) copied, 0.1143 s, 91.7 MB/s

ddを使用してi/oを同期する必要があります シークできない入力を処理します。言い換えると、パイプバッファを明示的にすると、問題がなくなります。それがdd です。ここでの不明な数量はyesです のバッファサイズ–ただし、それを既知にブロックすると 別のddの数量 次に、少し情報に基づいた乗算で ddを作成できます データのコピーに安全に使用できます(部分的な読み取りまたは書き込みによる破損のリスクはありません) count =で入力を任意に制限する場合でも 任意のPOSIXシステムで任意の入力タイプを使用し、1バイトを失うことはありません。

POSIX仕様の抜粋は次のとおりです。

  • ibs = expr
    • 入力ブロックサイズをバイト単位でexprで指定します (デフォルトは512)
  • obs = expr
    • 出力ブロックサイズをバイト単位でexprで指定します (デフォルトは512)
  • bs = expr
    • 入力ブロックサイズと出力ブロックサイズの両方をexprに設定します バイト、 ibs =に取って代わります およびobs= sync以外の変換がない場合 、 noerror 、および notrunc が指定されている場合、各入力ブロックは、短いブロックを集約せずに単一のブロックとして出力にコピーされます。
関連:端末に[メールで保護]を太字で表示するにはどうすればよいですか?

ここでは、この説明の一部についても詳しく説明しています。


Linux
  1. Netcatコマンドを使用して、Ubuntu20.04のネットワーク全体でデータを読み書きします

  2. 読み取り、書き込み、実行の権限を変更しますか?

  3. TCP_NODELAY と TCP_CORK をいつ使用する必要がありますか?

  1. Linuxターミナルでリダイレクトを使用して、どこからでもデータを読み書きできます

  2. Bashでは、いつエイリアスを作成し、いつスクリプトを作成し、いつ関数を作成するのですか?

  3. EINTR をチェックして関数呼び出しを繰り返すのはいつですか?

  1. bsdtar コマンド – テープ アーカイブ ファイルの読み取りと書き込み

  2. Cでシリアルポートを開き、読み書きする方法は?

  3. 基本データ型の copy_to_user() および copy_from_user()