「Dd」の版間の差分

提供: ArchWiki
ナビゲーションに移動 検索に移動
(参照を翻訳して追加)
 
(3人の利用者による、間の11版が非表示)
57行目: 57行目:
 
{{Note|指定するブロックサイズは、読み取りエラーの処理方法に影響します。以下をお読みください。データの回復には、[[ディスクのクローン#ddrescue を使う|ddrescue]] を使用してください。}}
 
{{Note|指定するブロックサイズは、読み取りエラーの処理方法に影響します。以下をお読みください。データの回復には、[[ディスクのクローン#ddrescue を使う|ddrescue]] を使用してください。}}
   
''dd'' ユーティリティには、技術的には「入力ブロックサイズ」(IBS)と「出力ブロックサイズ」(OBS)があります。{{ic|bs}} を設定すると、実質的に IBS と OBS の両方を設定することになります。通常、ブロックサイズが例えば 1MiB の場合、dd は 1024×1024 バイトを読み込み、同じバイト数を書き込みます。しかし、読み取りエラーが発生すると、事態はおかしくなります。多くの人は、{{ic|noerror,sync}} オプションを使うと、dd が「読み込みエラーをゼロで埋める」と思っているようですが、そうではありません。ドキュメントによると、dd は読み込み完了後に OBS から IBS のサイズを埋める、つまりブロックの最後にゼロを追加するのです。つまり、ディスクの場合、512 バイトの読み取りエラーが読み取りの最初に1回発生しただけで、事実上 1MB 全体がめちゃくちゃになってしまうのです: 12ERROR89 は 120000089 ではなく 128900000 となります。
+
''dd'' ユーティリティには、技術的には「入力ブロックサイズ」(IBS)と「出力ブロックサイズ」(OBS)があります。{{ic|bs}} を設定すると、実質的に IBS と OBS の両方を設定することになります。通常、ブロックサイズが例えば 1MiB の場合、dd は 1024×1024 バイトを読み込み、同じバイト数を書き込みます。しかし、読み取りエラーが発生すると、事態はおかしくなります。多くの人は、{{ic|noerror,sync}} オプションを使うと、dd が「読み込みエラーをゼロで埋める」と思っているようですが、そうではありません。ドキュメントによると、dd は読み込み完了後に OBS から IBS のサイズを埋める、つまりブロックの最後にゼロを追加するのです。つまり、ディスクの場合、512 バイトの読み取りエラーが読み取りの最初に1回発生しただけで、事実上 1MB 全体がめちゃくちゃになってしまうのです: 12ERROR89 は 120000089 ではなく 128900000 となります。
   
 
ディスクにエラーがないことが確認できれば、ブロックサイズを大きくしてコピーを進めることができ、コピーの速度が数倍向上します。例えば、Celeron 2.7GHz のシステムで、bs を 512 から 64K に変更すると、コピー速度が 35MB/s から 120MB/s になります。ただし、コピー元のディスクで発生した読み取りエラーは、コピー先のディスクではブロックエラーとして発生することに注意してください。つまり、512バイトのリードエラーは、出力先の 64 KiB ブロック全体をめちゃくちゃにします。
 
ディスクにエラーがないことが確認できれば、ブロックサイズを大きくしてコピーを進めることができ、コピーの速度が数倍向上します。例えば、Celeron 2.7GHz のシステムで、bs を 512 から 64K に変更すると、コピー速度が 35MB/s から 120MB/s になります。ただし、コピー元のディスクで発生した読み取りエラーは、コピー先のディスクではブロックエラーとして発生することに注意してください。つまり、512バイトのリードエラーは、出力先の 64 KiB ブロック全体をめちゃくちゃにします。
73行目: 73行目:
 
[[fdisk#パーティションテーブルのバックアップとリストア]] または [[gdisk#パーティションテーブルのバックアップとリストア]] を参照。
 
[[fdisk#パーティションテーブルのバックアップとリストア]] または [[gdisk#パーティションテーブルのバックアップとリストア]] を参照。
   
  +
=== ディスクイメージの作成 ===
=== Create disk image ===
 
   
  +
ライブ環境のメディアから起動し、ソースのハードドライブのパーティションがマウントされていないことを確認してください。
Boot from a live medium and make sure no partitions are mounted from the source hard drive.
 
   
  +
次に、外部のハードドライブをマウントし、ドライブをバックアップしてください:
Then mount the external hard drive and backup the drive:
 
   
 
# dd if=/dev/sda conv=sync,noerror bs=64K {{!}} gzip -c > ''/path/to/backup.img.gz''
 
# dd if=/dev/sda conv=sync,noerror bs=64K {{!}} gzip -c > ''/path/to/backup.img.gz''
   
  +
必要であれば (出力ファイルが [[FAT32]] ファイルシステム上に保存される場合など)、ディスクイメージを複数に分けてください ({{man|1|split}} も見てください):
If necessary (e.g. when the resulting files will be stored on a [[FAT32]] file system) split the disk image into multiple parts (see also {{man|1|split}}):
 
   
 
# dd if=/dev/sda conv=sync,noerror bs=64K {{!}} gzip -c {{!}} split -a3 -b2G - ''/path/to/backup.img.gz''
 
# dd if=/dev/sda conv=sync,noerror bs=64K {{!}} gzip -c {{!}} split -a3 -b2G - ''/path/to/backup.img.gz''
   
  +
ローカルに十分なディスクスペースがない場合、イメージを ''ssh'' を通して送ることもできます:
If there is not enough disk space locally, you may send the image through ''ssh'':
 
   
 
# dd if=/dev/sda conv=sync,noerror bs=64K {{!}} gzip -c {{!}} ssh user@local dd of=backup.img.gz
 
# dd if=/dev/sda conv=sync,noerror bs=64K {{!}} gzip -c {{!}} ssh user@local dd of=backup.img.gz
   
  +
最後に、イメージに保存されているパーティションテーブルを解釈するために必要な、ドライブのジオメトリ情報に関する追加情報を保存します。最も重要なのはシリンダーサイズです。
Finally, save extra information about the drive geometry necessary in order to interpret the partition table stored within the image. The most important of which is the cylinder size.
 
   
 
# fdisk -l /dev/sda > ''/path/to/list_fdisk.info''
 
# fdisk -l /dev/sda > ''/path/to/list_fdisk.info''
   
  +
{{Note|バックアップする HD のキャッシュの容量と同じブロックサイズ ({{ic|1=bs=}}) を使うと良いかもしれません。例えば、{{ic|1=bs=8192K}} は 8 MiB キャッシュでうまく行きます。この記事で説明されている 64 KiB は、デフォルトの {{ic|1=bs=512}} バイトよりも良いですが、より多くの {{ic|1=bs=}} を使えばより速く実行できます。}}
{{Note|You may wish to use a block size ({{ic|1=bs=}}) that is equal to the amount of cache on the HD you are backing up. For example, {{ic|1=bs=8192K}} works for an 8 MiB cache. The 64 KiB mentioned in this article is better than the default {{ic|1=bs=512}} bytes, but it will run faster with a larger {{ic|1=bs=}}.}}
 
   
  +
{{Tip|''gzip'' はデータ圧縮にシングルの CPU コアしか使用できません。そのせいで、データのスループットが最近のストレージの書き込みスピードよりかなり遅くなってしまいます。マルチコア圧縮でディスクイメージの作成をより速くするには、例えば {{Pkg|pigz}} などのパッケージをインストールし、上記の {{ic|gzip -c}} コマンドを {{ic|pigz -c}} に置き換えてください。巨大なディスクでは時間を節約できるかもしれません。また、他の圧縮アルゴリズム ({{Pkg|zstd}} など) を試しても良いかもしれません。}}
{{Tip|''gzip'' is only able to compress data using a single CPU core, which leads to a data throughput considerably lower than the write speeds on modern storage. In order to leverage multicore compression and create a disk image more quickly, one could for instance install the {{Pkg|pigz}} package, and simply replace the {{ic|gzip -c}} command above with {{ic|pigz -c}}. For large disks, this can potentially save hours.}}
 
   
 
=== システムの復元 ===
 
=== システムの復元 ===
148行目: 148行目:
 
== ディスク関連や他の使用場面 ==
 
== ディスク関連や他の使用場面 ==
   
As some readers might already realized, the {{man|1|dd}} core utility has an [https://unix.stackexchange.com/a/12538#12538 quite different] command-line syntax compared to other utilities. Moreover, while supporting [https://unix.stackexchange.com/a/12538#12538 some unique features not found in other commodity utilities], several default behaviour (and sometimes, inability) it has is either [https://www.pixelbeat.org/docs/coreutils-gotchas.html#dd less-ideal] or [[dd#Partial_read:_copied_data_is_smaller_than_requested|potential error-prone]] if applied to specific scenario. For that reason, users may want to use some alternatives that better in some aspects in lieu of the ''dd'' core utility.
+
既にお気づきの方もいらっしゃるかもしれませんが、{{man|1|dd}} コアユーティリティは他のユーティリティと比較して [https://unix.stackexchange.com/a/12538#12538 かなり異なる] コマンドラインのシンタックスを持っています。さらに、[https://unix.stackexchange.com/a/12538#12538 他のコモディティユーティリティにはないユニークな機能] をサポートしていますが、特定のシナリオに適用すると、[https://www.pixelbeat.org/docs/coreutils-gotchas.html#dd あまり理想的でない] [[dd#Partial_read:_copied_data_is_smaller_than_requested|potential error-prone]] デフォルト動作 (時には、できないこと) がいくつも存在します。そのため、ユーザーは ''dd'' コアユーティリティの代わりに、ある面ではより優れた代替品を使いたいと思うかもしれません。
   
  +
そうは言っても、''dd'' は [[coreutils|core utility]] であり、Arch や他の多くのシステムにデフォルトでインストールされているため、代替ユーティリティやより専門化されたユーティリティよりも好ましいことに注意する必要があります。システムに新しいパッケージをインストールするのは不便です。
That said, it is still worth to note that since ''dd'' is a [[coreutils|core utility]], which is installed by default on Arch and many other systems, is preferable to some alternatives or more specialized utilities if it is inconvenient to install a new package on your system.
 
   
  +
上記で説明した 2 つの側面をカバーするために、このセクションでは、他の汎用ユーティリティではほとんど見られない {{man|1|dd}} コア ユーティリティの機能を、[[Pacman/比較表]] の記事に似た形式で要約することに専念します。ただし、サンプルの量は、''dd'' のこれらの機能を調べるのに十分な量 (''ヒント:'' の ''ie'' または ''To'' 節で示されています) にできる限り少なく、単純に削減されています。サブセクションの下のボックス)、実践または疑似コードのいずれかにおいてです.
To cover the two aspects that addressed above, this section is dedicated to summarise the features of {{man|1|dd}} core utility that rarely found in other commodity utilities, in a form that resemble [[pacman/Rosetta]] article but with quantities of examples being cut down to as few and simple as possible to just enough to examine these features of ''dd'' (as denoted by ''i.e.'' or ''To''-clause in "Tip:" box under subsection), either in practice or ''pseudocode''.
 
   
  +
{{note|この専用セクションを適切な長さに保つために、代替ユーティリティの比較には、公式リポジトリにあるパッケージのみが含まれています。この場合、言及されている他のユーティリティよりも明らかな利点があり、必要に応じて詳細が記載されています。<br>その他の代替ユーティリティについては、[[coreutils#dd の代替]] を参照して下さい。}}
{{note|To keep this dedicated section in a reasonable length, comparison of alternative utilities only includes packages found in official repositories, in which case has obvious advantage over others being mentioned, and written in more details if necessary.<br>For more alternatives, see [[coreutils#dd alternatives]].}}
 
   
 
=== バイナリファイルにブロック単位のパッチをインプレースに適用する ===
 
=== バイナリファイルにブロック単位のパッチをインプレースに適用する ===
It is not an uncommon practice to use ''dd'' as a feature-limited binary file patcher in automated shell scripts since it is capable to {{ic|seek}} the output file by given offset before writing, and to block-by-block (or byte-y-byte if {{ic|1=bs=1}}) in-place patching the output file by adding the {{ic|1=conv=notrunc}} option.
 
   
  +
自動シェルスクリプトで機能が限定されたバイナリファイルパッチャーとして ''dd'' を使用することは珍しいことではありません。これは、書き込み前に指定されたオフセットによって出力ファイルを {{ic|seek}} することができ、ブロックすることができるためです。 {{ic|1=conv=notrunc}} オプションを追加して、出力ファイルにブロック単位 (または {{ic|1=bs=1}} の場合はバイト y バイト) でインプレースパッチを適用します。
For example, to modify the timestamp part of first member in a {{man|5|cpio|Portable ASCII Format}} archive, which starts at the 49th byte of the file (or with offset of {{ic|0x30}} if you prefer hex notation):
 
  +
  +
たとえば、{{man|5|cpio|Portable ASCII Format}} アーカイブ内の最初のメンバーのタイムスタンプ部分を変更するには、ファイルの 49 番目のバイトから始まります (または、次の場合は {{ic|0x30}} のオフセットで始まります)。16 進表記を好む場合):
   
 
$ touch a-randomly-chosen-file
 
$ touch a-randomly-chosen-file
166行目: 167行目:
 
$ printf '%011o' "$(date -d "2019-12-21 00:00:00" +%s)" | dd conv=notrunc of=example-modify-ts.cpio seek='''48''' oflag=seek_bytes
 
$ printf '%011o' "$(date -d "2019-12-21 00:00:00" +%s)" | dd conv=notrunc of=example-modify-ts.cpio seek='''48''' oflag=seek_bytes
   
{{note|The currently undocumented [https://github.com/coreutils/coreutils/commit/140eca15c4a3d3213629a048cc307fde0d094738 {{ic|seek_bytes}} output flag] is specified above for seeking the output in offset of bytes instead of blocks before starting to {{man|2|write}} to output.}}
+
{{note|現在文書化されていない [https://github.com/coreutils/coreutils/commit/140eca15c4a3d3213629a048cc307fde0d094738 {{ic|seek_bytes}} 出力フラグ] は、出力への {{man|2|write}} を開始する前にブロックではなくバイトのオフセットで出力をシークするために上記に追加されています。}}
   
{{tip|To print byte stream from command-line input hex notation, use {{man|1|basenc|base16}} and/or {{man|1|printf}}.}}
+
{{tip|コマンドライン入力の 16 進表記からバイト ストリームを出力するには、{{man|1|basenc|base16}} および/または {{man|1|printf}} を使用します。}}
   
  +
{{tip|この機能では、''dd'' の代わりに、シェルが開いたファイルディスクリプタに対して {{man|2|lseek}} を呼び出すことをサポートするシェルを使用することを検討することができます。:
{{tip|In this feature grid (''i.e.'' {{man|2|write}} ''with offset, with'' no truncation), instead of using ''dd'', one may consider using a shell that supporting {{man|2|lseek}} operation on shell-opened file descriptor if in case of:
 
   
  +
* ''dd'' の入力ファイルは {{man|2|splice}} システムコールを利用するプログラムと接続されたパイプであり、ユーザはより良いパフォーマンスのために ''dd'' の不必要なユーザ空間 I/O を避けたいと考えています。
* the input file of ''dd'' is a pipe connected with a program that utilize {{man|2|splice}} system call, and the user want to avoid unnecessary userspace I/O of ''dd'' for a better performance
 
  +
* または、シェルスクリプトのループ内で頻繁に {{man|2|fork}} が発生するのを避け、パフォーマンスペナルティを下げたい。
* or, to avoid frequently {{man|2|fork}} in shell script loop to reduce performance penality
 
   
  +
その場合、まずそのシェルにファイルディスクリプタを開かせ、そのファイルディスクリプタに対してシーク操作を行い、{{man|2|splice}} システムコールを使う対応するユーティリティの出力端としてこのファイルディスクリプタを割り当てる必要があります(あるいは{{man|1|zshmodules|sysseek}} のようにフォークしないシェル内蔵コマンドもあります):{{hc|$ zsh|<nowiki>$ local +xr openToWriteFD
Then it would be necessary to let that shell open the file descriptor at first, and perform some seeking operation on the file descriptor to assign this file descriptor as output end of corresponding utility that use {{man|2|splice}} system call (or a shell builtin command does not forking, as in following example of {{man|1|zshmodules|sysseek}}):{{hc|$ zsh|<nowiki>$ local +xr openToWriteFD
 
 
$ zmodload zsh/system
 
$ zmodload zsh/system
 
$ sysopen -wo cloexec -u openToWriteFD example-modify-ts.cpio
 
$ sysopen -wo cloexec -u openToWriteFD example-modify-ts.cpio
 
$ sysseek -u $openToWriteFD 48
 
$ sysseek -u $openToWriteFD 48
 
$ printf '%011o' "$(date -d "2019-12-21 00:00:00" +%s)" >&${openToWriteFD}</nowiki>}}
 
$ printf '%011o' "$(date -d "2019-12-21 00:00:00" +%s)" >&${openToWriteFD}</nowiki>}}
  +
{{warning|オフセットを使用して書き込む必要があるプログラムが実際に {{man|2|splice}} を使用していることを確認できない場合は、このアプローチの使用を避けてください (これは、プログラムが出力に対していかなる種類のシークや切り捨ても実行しないことを意味します)。一部のプログラムは、この動作がコマンド ラインフラグで指定されていない場合でも、入力/出力ファイル記述子を自動的にシーク/切り捨てることがあります。これにより、シェルの {{man|3|lseek}} 呼び出しが無効になったり、開いているファイル記述子が予期せず切り詰められたりすることがあります。}}}}
{{warning|Avoiding using this approach if you cannot ensure the program which you need it write with offset really utilize {{man|2|splice}} (which implies that the program does not perform any kind of seeking or truncating on its output). Some programs may seek/truncate on input/output file descriptor by themselves even if this behaviour is unspecified on command line flags, which invalidates your shell's {{man|3|lseek}} call, or unexpectedly truncates on opened file descriptor.}}}}
 
   
 
=== VFAT ファイルシステムイメージのボリュームラベルを表示する ===
 
=== VFAT ファイルシステムイメージのボリュームラベルを表示する ===
{{tip|For this specific scenario, a more practical choice is {{pkg|file}}.}}
 
   
  +
{{tip|この特定のシナリオでは、より現実的な選択肢は {{pkg|file}} です。}}
To read the filesystem [https://wiki.osdev.org/FAT#FAT_32_2 volume label of an VFAT] image file, which should be in total length of 11 bytes that padded by ASCII spaces, with an offset of {{ic|0x047}}:
 
  +
  +
ファイルシステム [https://wiki.osdev.org/FAT#FAT_32_2 VFAT のボリュームラベル] イメージファイルを読み取るには、ASCII スペースが埋め込まれた全長 11 バイトで、オフセットは {{ic|0x047}} です。:
   
 
$ truncate -s ''33M'' empty-hole.img
 
$ truncate -s ''33M'' empty-hole.img
191行目: 193行目:
   
 
$ dd iflag=skip_bytes,count_bytes count=11 skip=$((0x047)) if=empty-hole.img | sed -e 's% *$%%'
 
$ dd iflag=skip_bytes,count_bytes count=11 skip=$((0x047)) if=empty-hole.img | sed -e 's% *$%%'
{{note|[https://github.com/coreutils/coreutils/commit/140eca15c4a3d3213629a048cc307fde0d094738 Both input flags are currently undocumented]:
+
{{note|[https://github.com/coreutils/coreutils/commit/140eca15c4a3d3213629a048cc307fde0d094738 両方の入力フラグは現在文書化されていません]:
  +
* 以前の {{ic|skip_bytes}} は、入力ファイルから {{man|2|read}} を開始する前に、ブロック数ではなくバイト数でオフセットしてシーク (シークできない入力の場合は ''skip'') するように ''dd'' に指示しました。
* The former {{ic|skip_bytes}} instruct ''dd'' to seek (or ''skip'' if input is not seekable) on input file by offset in quatity of byte instead of number of blocks before starting to {{man|2|read}} from it.
 
  +
* {{ic|count_bytes}} では、ブロック数ではなく、入力ファイルからコピーするブロックの総量を ''バイト'' で指定することができます。このオプションを指定しても部分的な {{man|2|read}} の対象となる可能性があるので混乱するかもしれませんが、この挙動をより理解するために [[dd#部分読み取り: コピーされたデータは要求されたデータよりも小さい|input block {{ic|count}}]] の小数値と考えるようにします。}}
* The later {{ic|count_bytes}} allow user to specifiy the total quantity of blocks to copy from input file ''in byte'', instead of a number of blocks. It could be confusing since specifing this option could still subject to partial {{man|2|read}}, think it like a fractional value of [[dd#Partial_read:_copied_data_is_smaller_than_requested|input block {{ic|count}}]] to better understand this behaviour.}}
 
   
{{tip|''To transfer data from input (with an offset) to output within given length'', in shell scripting, one may also consider {{man|1|curl|r,}} as a commodity alternative that use range notation instead.{{note|''curl'' does not support seeking/skipping when input file is a device/pipe, another alternative {{man|1|socat}} does support these operation on input file (incl. block device, ''excl. pipe and character device'') but is less commodifying than ''curl'':{{bc|<nowiki>$ socat -u -,seek=$((0x047)),readbytes=11 - < empty-hole.img | sed -e 's% *$%%'</nowiki>}}}}}}
+
{{tip|''指定された長さ内で入力 (オフセット付き) から出力にデータを転送するには''、シェル スクリプトでは、代わりに範囲表記を使用する代替手段として {{man|1|curl|r,}} を考慮することもできます。{{note|''curl'' は、入力ファイルがデバイス/パイプである場合のシーク/スキップをサポートしません。別の代替手段 {{man|1|socat}} は、入力ファイルに対するこれらの操作をサポートします (ブロックデバイスを含む、パイプを除く) 文字デバイス'') ですが、''curl'' ほどコモディティ化されていません。:{{bc|<nowiki>$ socat -u -,seek=$((0x047)),readbytes=11 - < empty-hole.img | sed -e 's% *$%%'</nowiki>}}}}}}
   
 
=== パイプで繋がれたコマンド間で sponge する ===
 
=== パイプで繋がれたコマンド間で sponge する ===
{{tip|As already noted in title, a practical choice for this specific scenario is {{man|1|sponge}}, which supports atomic write by writing to {{ic|<nowiki>${TMPDIR:-/tmp}</nowiki>}} at first.}}
 
   
  +
{{tip|タイトルですでに述べたように、この特定のシナリオでの実際的な選択肢は {{ic|<nowiki>${TMPDIR:-/tmp}</nowiki> への書き込みによるアトミック書き込みをサポートする {{man|1|sponge}} です}}}}
In following example, to avoid unnecessary long-lasting TCP connection on input end if the output end blocks longer than expected, one may put a ''dd'' between two commands with an output block size certainly larger than input while still reasonably smaller than available memory:
 
  +
  +
次の例では、出力側のブロックが予想より長くなった場合に、入力側で不必要に長く続く TCP 接続を避けるために、2 つのコマンドの間に ''dd'' を挿入し、出力ブロックサイズは入力よりも確実に大きく、それでも使用可能なメモリよりはかなり小さいものにすることができます。
   
 
$ curl -qgsfL <nowiki>http://example.org/mirrors/ftp.archlinux.org/mirrored.md5deep</nowiki> | dd ibs=128k obs=200M | ''poor-mirroring-script-that-perform-mirroring-on-input-paths-line-by-line-wo-buffer-entire-list-first''
 
$ curl -qgsfL <nowiki>http://example.org/mirrors/ftp.archlinux.org/mirrored.md5deep</nowiki> | dd ibs=128k obs=200M | ''poor-mirroring-script-that-perform-mirroring-on-input-paths-line-by-line-wo-buffer-entire-list-first''
   
  +
{{warning|''dd'' はコピー操作全体を開始する前に出力ファイルを切り詰めるため、これを {{man|1|sponge}} の一般的な代替手段として考慮しないでください。}}
{{warning|It should never be considered as a generic alternative to {{man|1|sponge}} as ''dd'' truncates the output file before starting the entire copy operation.}}
 
   
 
=== サイズの制限付きでデータを転送する ===
 
=== サイズの制限付きでデータを転送する ===
  +
It's a common practice to use ''dd'' in a data streaming shell script for limiting total length of data that a piped command may consume. For example, to inspect an ustar header block ({{man|5|tar|POSIX ustar Archives}}) using a shell script function in a streaming manner:
 
  +
データストリーミングのシェルスクリプトで ''dd'' を使用すると、パイプコマンドで消費されるデータの合計長を制限することができるのは一般的です。例えば、ustar ヘッダブロック ({{man|5|tar|POSIX ustar Archives}}) をシェルスクリプトの機能を使ってストリーミング方式で検査する場合です:
{{note|The {{ic|B}} suffix in argument to {{ic|count}} option is a [https://github.com/coreutils/coreutils/commit/97e9778296ead515e77a64942b84f88dcf36a176 newerly introduced] feature as of GNU coreutils v9.1 that has same effect of [[Dd#Printing_volume_label_of_a_VFAT_filesystem_image_(i.e._read_in_given_length,_with_offset)|{{ic|count_bytes}} input flag]], is potentially confusable with option in forms like {{ic|1=count=256k}} which indicate ''dd'' to copy 262144 input blocks instead of bytes.}}
 
  +
{{Note|{{ic|count}} オプションの引数にある {{ic|B}} サフィックスは GNU coreutils v9.1 の [https://github.com/coreutils/coreutils/commit/97e9778296ead515e77a64942b84f88dcf36a176 新しく導入された] 機能で、 [[dd#VFAT ファイルシステムイメージのボリュームラベルを表示する]] と同じ効果を持っている。 この機能は、{{ic|1=count=256k}}のように、''dd'' がバイトではなく262144個の入力ブロックをコピーすることを示すオプションと混同される可能性があります。}}
 
{{bc|<nowiki>hexdump-field() {
 
{{bc|<nowiki>hexdump-field() {
 
set -o pipefail
 
set -o pipefail
242行目: 246行目:
 
}</nowiki>}}
 
}</nowiki>}}
 
$ bsdtar -cf - /dev/tty /dev/null 2>&- | dd count=1 skip=1 status=none | inspect-tar-header-block
 
$ bsdtar -cf - /dev/tty /dev/null 2>&- | dd count=1 skip=1 status=none | inspect-tar-header-block
  +
{{tip|''指定された長さ内で入力から出力にデータをストリーミングするには'' という代替案は、{{man|2|splice}} システムコールをサポートする {{man|1|pv|S,}} です。
{{tip|''To streaming data from input to output within given length'', an alternative is {{man|1|pv|S,}} which supports {{man|2|splice}} system call.
 
{{note|Another candidate alternative is {{man|1|head|c}}, though [[coreutils#Alternatives|implementation other than GNU coreutils]] and glibc [https://unix.stackexchange.com/a/12538#12538 may consume more data than requested], causing data misalignment issue in a streamingly shell script.}}}}
+
{{note|もう 1 つの代替候補は {{man|1|head|c}} ですが、[[coreutils#Alternatives|GNU coreutils 以外の実装]] glibc [https://unix.stackexchange.com/a/12538#12538 は消費する可能性があります]要求されたデータよりも多くのデータ] が発生し、ストリーミングシェルスクリプトでデータの不整合の問題が発生します。}}}}
  +
{{Tip|上記の機能グリッドに加えて、入力ファイルがストリーミング前に特定のオフセットによって {{man|2|lseek}} され、''dd'' の出力端がプログラムに接続されたパイプである場合は、{{man|2|splice}} の場合、代わりに次の使用を検討できます。
{{Tip|In addition to above feature grid, if input file shall be {{man|2|lseek}}'d by specific offset before streaming, and the output end of ''dd'' is a pipe connected with a program utilize {{man|2|splice}}, then, as an alternative, one may consider use:
 
  +
* シーク機能が組み込まれたシェル (''すでに述べたように [[#前のサブセクションでの代替として、バイナリファイルにブロックごとにインプレースでパッチを適用する'']])
* a shell with builtin seeking capability (''as already mentioned [[#Patching a binary file, block-by-block in-place|as alternative in a previous subsection]].'')
 
* or, a Bourne-like shell (e.g. [[bash]]), with help of {{man|1|xxd|s}} for one-off {{man|2|lseek}} on shell-opened file descriptor,
+
* または、Bourne のようなシェル (例:[[bash]])、シェルで開かれたファイル記述子に対する 1 回限りの {{man|2|lseek}} 用の {{man|1|xxd|s}} の助けを借りて、
and {{man|1|pv|S,}} (''mentioned above'') as in following [[bash]] example (assuming that file descriptor has not allocated in shell by {{ic|ls -l /proc/self/fd}} in bash at first):{{hc|$ bash|<nowiki>$ exec 9<dummy-but-rather-large.img
+
次の [[bash]] の例のように {{man|1|pv|S,}} (''前述'') を実行します (ファイル記述子が {{ic|ls -l /proc によってシェルに割り当てられていないと仮定します) 最初は bash の /self/fd}} {{hc|$ bash|<nowiki>$ exec 9<dummy-but-rather-large.img
 
$ xxd -g 0 -l 0 -s $((0x47ffff)) <&9
 
$ xxd -g 0 -l 0 -s $((0x47ffff)) <&9
 
$ pv -qSs 104857601200 <&9 |</nowiki> ''program-that-process-load-of-data-but-does-not-limit-read-length-as-desired-nor-support-offset-read''
 
$ pv -qSs 104857601200 <&9 |</nowiki> ''program-that-process-load-of-data-but-does-not-limit-read-length-as-desired-nor-support-offset-read''
$ exec 9<&-}}{{note|Though incompatible with POSIX and some non-GNU implementation, it's feasible to replace the usage of {{man|1|xxd|s}} in above example with ''dd'' in conjunction of {{ic|1=count=0}} and {{ic|skip}} options as [https://github.com/coreutils/coreutils/blob/4fd708810ce0e0d967c4c14e1ff2ff7b43440b58/tests/dd/skip-seek-past-file.sh#L74 an example in coreutils test suite].}}}}
+
$ exec 9<&-}}{{note|POSIX および一部の非 GNU 実装とは互換性がありませんが、上記の例の {{man|1|xxd|s}} の使用を、{{ic|1=count=0}} と組み合わせた ''dd'' に置き換えることは可能です。および {{ic|skip}} オプション [https://github.com/coreutils/coreutils/blob/4fd708810ce0e0d967c4c14e1ff2ff7b43440b58/tests/dd/skip-seek-past-file.sh#L74 coreutils テストスイートの例]}}}}
   
 
=== ブータブルなディスクイメージをブロックデバイスに書き込み、任意で進捗情報を表示する ===
 
=== ブータブルなディスクイメージをブロックデバイスに書き込み、任意で進捗情報を表示する ===
   
  +
その場合に最も適合性が低い可能性がある ''dd'' を含むコモディティ ユーティリティの例については、[[USB インストールメディア#基本的なコマンドラインユーティリティを使う]] を参照してください。
See [[USB flash installation medium#Using_basic_command_line_utilities]] for examples of commodity utilities include the potential least adapted ''dd'' for that case.
 
  +
{{tip|''ファイルの内容をブロックデバイスに書き込む (進行状況インジケーター付き)'' という代替案として、{{man|1|dd_rescue|W}} が推奨されます。デバイス上の古いバージョンのイメージを新しいバージョンで上書きする場合、不要な書き込みを回避できます。}}
{{tip|''To write the content of a file to block device (with progress indicator)'', a suggested alternative is {{man|1|dd_rescue|W}}. It is capable to avoid unnecessary writing in case of overwriting the old version of image on device with a newer version.}}
 
   
  +
== トラブルシューティング ==
== Troubleshooting ==
 
{{Style|The troubleshooting section currently only hold one subsection that describes the logic of dd's {{ic|count}} option. Merge this into a previous section for a better overall reading experience in linear order.}}
 
=== Partial read: copied data is smaller than requested ===
 
   
  +
=== 部分読み取り: コピーされたデータは要求されたデータよりも小さい ===
Files created with ''dd'' can end up with a smaller size than requested if a full input block is not available for various reasons (i.e. the underlying {{man|2|read}} system call returns early.) This can happen when reading from a {{man|7|pipe}}, or when reading a device file like {{ic|/dev/urandom}} and {{ic|/dev/random}} (e.g. due to [https://unix.stackexchange.com/a/178957#178957 hardcoded limitation of underlying kernel device driver] or insufficient entropy.), in conjunction of {{ic|1=count=''n''}} option where {{ic|''n''}} is the number of input block(s) to copy to output.
 
   
  +
[https://www.gnu.org/software/coreutils/manual/html_node/dd] のように、現時点で完全な入力ブロックが利用できない場合、''dd'' で作成されたファイルは要求されたサイズよりも小さくなる可能性があります。[https://www.gnu.org/software/coreutils/manual/html_node/dd-invocation.html#dd-invocation per ドキュメント]:
It is possible, but not guaranteed, that ''dd'' will warn you about such kind of issue:
 
  +
  +
:''さらに、データ変換する {{ic|conv}} 被演算子 ''(つまり、この Wiki 記事のようなオプション)'' が指定されていない場合、入力は読み取られるとすぐに出力にコピーされます。ブロックサイズより小さいです。''
  +
  +
Linuxでは、{{man|2|read}} システムコールは {{man|7|pipe}} から読むとき、または {{ic|/dev/urandom}} や {{ic|/dev/random}} などのデバイスファイルを読むときに早く戻ることがあります (つまり、''部分読み'') (例えば、[https://unix.stackexchange.com/a/178957#178957 基礎となるカーネルデバイスドライバーのハードコーディングされた制限] またはエントロピーが不十分です) ここで {{ic|''n''}} は出力にコピーする入力ブロックの最大数 (''潜在的な部分'') を制限します。
  +
  +
可能性はありますが、保証はできません。''dd'' がそのような種類の問題について警告する可能性があります。
   
 
dd: warning: partial read (''X'' bytes); suggest iflag=fullblock
 
dd: warning: partial read (''X'' bytes); suggest iflag=fullblock
   
  +
解決策は、警告にあるように、入力ファイルオプションに加えて {{ic|1=iflag=fullblock}} オプションを ''dd'' コマンドに追加することです。たとえば、合計長が 40 MB のランダム データで満たされた新しいファイルを作成するには、次のようにします。
The solution is to do as the warning says, add {{ic|1=iflag=fullblock}} option in addition to the input file option to the ''dd'' command. For example, to create a new file filled up with random data in total length of 40 megabytes:
 
   
 
$ dd if=/dev/urandom of=new-file-filled-by-urandom.bin bs=40M count=1 iflag=fullblock
 
$ dd if=/dev/urandom of=new-file-filled-by-urandom.bin bs=40M count=1 iflag=fullblock
   
  +
{{Note|パイプや特殊なデバイスのファイルから読み込む際に、{{ic|1=count=''n''}} オプションを指定して、ファイルの一部を固定長でコピーすることが推奨されます、また、[[dd#ブートローダーの削除|デバイスの一部]] や [[ディスクの完全消去/ヒントとテクニック#単体ファイルの消去|ファイル]] を [[ディスクの完全消去|完全消去]] する場合は、{{ic|1=iflag=fullblock}} オプションを追加して''dd'' コマンドで行うことを常に強くお勧めします。}}
{{Note|When reading from a pipe or a special device file like we just mentioned below for copying a portion of file in a fixed length with {{ic|1=count=''n''}} option being specified, it is suggested to, or always strongly recommended to add the {{ic|1=iflag=fullblock}} option to the ''dd'' command if in case of [[Securely wipe disk|wiping]] a [[#Remove bootloader|portion of device]] or [[Securely wipe disk/Tips and tricks#Wipe a single file|file]].}}
 
   
When reading from a pipe, [https://unix.stackexchange.com/questions/556016/cat-dd-pipe-causes-partial-reads-without-iflag-fullblock-why-truncated-to-128 an alternative] to {{ic|1=iflag=fullblock}} is to limit {{ic|bs}} to the {{ic|PIPE_BUF}} constant value as defined in [https://elixir.bootlin.com/linux/latest/A/ident/PIPE_BUF {{ic|linux/limits.h}}] to make the {{man|7|pipe}} I/O atomic. For example, to prepare a text file filled up will random alphanumeric string in total length of 5 megabytes:
+
パイプから読み込む場合、{{ic|1=iflag=fullblock}} [https://unix.stackexchange.com/questions/556016/cat-dd-pipe-causes-partial-reads-without-iflag-fullblock-why-truncated-to-128 代替案] として、{{ic|bs}} [https://elixir.bootlin.com/linux/latest/A/ident/PIPE_BUF {{ic|linux/limits.h}}] で定義されている {{ic|PIPE_BUF}} 定数に制限して {{man|7|pipe}} I/O を原子化します。例えば、全長5メガバイトのランダムな英数字で埋め尽くされたテキストファイルを用意する場合、以下のようになります:
   
 
$ LC_ALL=C tr -dc '[:alnum:]' </dev/urandom | dd of=passtext-5m.txt bs='''4k''' count=1280
 
$ LC_ALL=C tr -dc '[:alnum:]' </dev/urandom | dd of=passtext-5m.txt bs='''4k''' count=1280
   
  +
出力ファイルはパイプではないため、(''入力'') パイプと (''出力'') ディスク上のファイル。たとえば、出力ファイルのより効率的なブロック サイズを設定するには、次のようにします。
Since the output file is not a pipe, one may prefer to use {{ic|1=ibs}} and {{ic|1=obs}} options to set block size separately for the (''input'') pipe and the (''output'') on-disk file. For example, to set a more efficient block size for output file:
 
   
 
$ LC_ALL=C tr -dc '[:alnum:]' </dev/urandom | dd of=passtext-5m.txt ibs=4k obs=''64k'' count=1280
 
$ LC_ALL=C tr -dc '[:alnum:]' </dev/urandom | dd of=passtext-5m.txt ibs=4k obs=''64k'' count=1280
   
  +
{{tip|状況によっては、出力ブロックサイズを入力ブロックサイズと同じ値に保つだけで、{{ic|PIPE_BUF}} 定数で定義された値がすでに最適である場合があります。}}
{{tip|In some circumstances, merely keep the the output block size the same the value as input block size with a value defined by {{ic|PIPE_BUF}} constant may already be optimal.}}
 
  +
  +
=== 総転送バイト数の読み出しが間違っている ===
  +
  +
以下の概念実証のように、出力への書き込み時にエラーが発生した場合 (例えば、SIGPIPE、欠陥のある媒体、または誤ってターゲットネットワークブロックデバイスを切断したことによる ''部分書き込み'')、読み出された総転送バイト数は実際よりも大きくなる可能性があります:第2の ''dd'' は明らかに512200バイト以上を読みませんが、第1の ''dd'' インスタンスはまだ不正確なバイト数512400バイトを報告します:
  +
  +
$ yes 'x' | dd bs=4096 count=512400B | dd ibs=1 count=512200 status=none >/dev/null
  +
125+1 records in
  +
125+1 records out
  +
512400 bytes (512 kB, 500 KiB) copied, 10.7137 s, 47.8 kB/s
  +
  +
上記の PoC のように中断された転送を再開する場合、"+" 記号の前の数字で示されるように、既にコピーされた全出力ブロックの数の読み出しのみに依存することをお勧めします。
  +
{{Note|{{ic|1=iflag=fullblock}} オプションを追加しても、部分I/Oブロック数が1より大きい場合は、部分 I/O が2回以上発生したことになります。 この場合、確実に転送を再開するために、次のことをお勧めします:
  +
* 潜在的な欠陥媒体の部分読み出しに柔軟に対処するために、代わりに [[ddrescue]] を使用して転送を再実行する。
  +
* ネットワーク接続が悪い状態で nbd に書き込む場合、{{man|1|dd_rescue}} を使って直接 I/O で転送を再実行する。
  +
* 欠陥のある媒体への書き込みを避けることができます。}}
  +
  +
== 参照 ==
  +
  +
* {{man|1p|dd}}: の [[man ページ|manpage]] dd コアユーティリティ POSIX 仕様

2024年2月20日 (火) 19:35時点における最新版

関連記事

dd はファイルの変換とコピーを主な目的とする コアユーティリティ です。

cp と同様にデフォルトでは dd はファイルのビットごとのコピーを作成しますが、低レベルの I/O フロー制御機能を備えています。

詳細は、dd(1) またはフルドキュメントを参照してください。

ヒント: デフォルトでは、dd はタスクが完了するまで何も出力しません。操作の進行状況を監視するには、コマンドに status=progress オプションを追加します。
警告: この種のコマンドはどれも、データを不可逆的に破壊する可能性があるため、dd の使用には細心の注意を払う必要があります。

インストール

dd は GNU coreutils の一部です。このパッケージ内の他のユーティリティについては、Core utilities を参照してください。

ディスクの複製と復元

dd コマンドはシンプルでありながら多機能で強力なツールです。ファイルシステムの種類や OS に関係なく、コピー元からコピー先へブロック単位でコピーすることができます。ライブ CD のようなライブ環境から dd を使用するのが便利です。

警告: このタイプのコマンドと同様に使用時には十分な注意が必要です。さもないと、データが破壊される可能性があります。入力ファイル (if=) と出力ファイル (of=) の順番を覚えておいて、逆にしないでください。出力先のドライブやパーティション (of=) のサイズが、入力元 (if=) と同じかそれ以上である事を常に確認してください。

パーティションの複製

物理ディスク /dev/sda のパーティション 1 から、物理ディスク /dev/sdb のパーティション 1 へ:

# dd if=/dev/sda1 of=/dev/sdb1 bs=64K conv=noerror,sync status=progress
ノート: 出力パーティション of= (この例では sdb1) が存在しない場合、dd はこの名前のファイルを作成し、ルートファイルシステムをいっぱいにしてしまうので注意が必要です。

ハードディスク全体の複製

物理ディスク /dev/sda から物理ディスク /dev/sdb へ:

# dd if=/dev/sda of=/dev/sdb bs=64K conv=noerror,sync status=progress

このコマンドは、パーティションテーブル、ブートローダー、すべてのパーティション、UUID、データを含むドライブ全体を複製します。

  • bs= はブロックサイズを設定します。デフォルトは512バイトで、これは1980年代前半以降のハードドライブの「古典」的なブロックサイズですが、最も便利なものではありません。64KBや128KBなど、より大きな値を使用してください。また、「ブロックサイズ」だけでなく、読み取りエラーの伝搬にも影響を与えるため、下記の警告をお読みください。詳細は、[1][2] を参照して、最適な bs 値を見つけてください。
  • noerror はすべての読み取りエラーを無視して操作を続けるように dd に指示します。dd のデフォルトの動作は、いかなるエラーでも停止します。
  • sync は読み込みエラーがあった場合、入力ブロックをゼロで埋め、データのオフセットは同期されたままになります (読み込みエラーが疑われる場合、sync を用いた際の読み込みエラーの挙動に関する下記の詳細な説明を見てください)。
  • status=progress は、操作がいつ完了するかを推測するために使用できる転送統計を表示します。
ノート: 指定するブロックサイズは、読み取りエラーの処理方法に影響します。以下をお読みください。データの回復には、ddrescue を使用してください。

dd ユーティリティには、技術的には「入力ブロックサイズ」(IBS)と「出力ブロックサイズ」(OBS)があります。bs を設定すると、実質的に IBS と OBS の両方を設定することになります。通常、ブロックサイズが例えば 1MiB の場合、dd は 1024×1024 バイトを読み込み、同じバイト数を書き込みます。しかし、読み取りエラーが発生すると、事態はおかしくなります。多くの人は、noerror,sync オプションを使うと、dd が「読み込みエラーをゼロで埋める」と思っているようですが、そうではありません。ドキュメントによると、dd は読み込み完了後に OBS から IBS のサイズを埋める、つまりブロックの最後にゼロを追加するのです。つまり、ディスクの場合、512 バイトの読み取りエラーが読み取りの最初に1回発生しただけで、事実上 1MB 全体がめちゃくちゃになってしまうのです: 12ERROR89 は 120000089 ではなく 128900000 となります。

ディスクにエラーがないことが確認できれば、ブロックサイズを大きくしてコピーを進めることができ、コピーの速度が数倍向上します。例えば、Celeron 2.7GHz のシステムで、bs を 512 から 64K に変更すると、コピー速度が 35MB/s から 120MB/s になります。ただし、コピー元のディスクで発生した読み取りエラーは、コピー先のディスクではブロックエラーとして発生することに注意してください。つまり、512バイトのリードエラーは、出力先の 64 KiB ブロック全体をめちゃくちゃにします。

ヒント: dd の進行状況を表示するためには、status=progress オプションを使用してください。詳細については、dd(1) を参照してください。
ノート:
  • ext2/3/4 ファイルシステムの UUID を一意な状態に戻すには、すべてのパーティションで、tune2fs /dev/sdXY -U random を使用してください。スワップパーティションの場合は、代わりに、mkswap -U random /dev/sdXY を使ってください。
  • GPT ディスクを複製する場合、sgdisk を使うことで、ディスクとパーティションの GUID をランダム化し、GUID の一意性を保つことができます。
  • dd によるパーティションテーブルの変更はカーネルには登録されません。再起動せずに変更を通知するには、partprobe (GNU Parted の一部)のようなユーティリティを使ってください。

パーティションテーブルのバックアップ

fdisk#パーティションテーブルのバックアップとリストア または gdisk#パーティションテーブルのバックアップとリストア を参照。

ディスクイメージの作成

ライブ環境のメディアから起動し、ソースのハードドライブのパーティションがマウントされていないことを確認してください。

次に、外部のハードドライブをマウントし、ドライブをバックアップしてください:

# dd if=/dev/sda conv=sync,noerror bs=64K | gzip -c  > /path/to/backup.img.gz

必要であれば (出力ファイルが FAT32 ファイルシステム上に保存される場合など)、ディスクイメージを複数に分けてください (split(1) も見てください):

# dd if=/dev/sda conv=sync,noerror bs=64K | gzip -c | split -a3 -b2G - /path/to/backup.img.gz

ローカルに十分なディスクスペースがない場合、イメージを ssh を通して送ることもできます:

# dd if=/dev/sda conv=sync,noerror bs=64K | gzip -c | ssh user@local dd of=backup.img.gz

最後に、イメージに保存されているパーティションテーブルを解釈するために必要な、ドライブのジオメトリ情報に関する追加情報を保存します。最も重要なのはシリンダーサイズです。

# fdisk -l /dev/sda > /path/to/list_fdisk.info
ノート: バックアップする HD のキャッシュの容量と同じブロックサイズ (bs=) を使うと良いかもしれません。例えば、bs=8192K は 8 MiB キャッシュでうまく行きます。この記事で説明されている 64 KiB は、デフォルトの bs=512 バイトよりも良いですが、より多くの bs= を使えばより速く実行できます。
ヒント: gzip はデータ圧縮にシングルの CPU コアしか使用できません。そのせいで、データのスループットが最近のストレージの書き込みスピードよりかなり遅くなってしまいます。マルチコア圧縮でディスクイメージの作成をより速くするには、例えば pigz などのパッケージをインストールし、上記の gzip -c コマンドを pigz -c に置き換えてください。巨大なディスクでは時間を節約できるかもしれません。また、他の圧縮アルゴリズム (zstd など) を試しても良いかもしれません。

システムの復元

システムを復元するには:

# gunzip -c /path/to/backup.img.gz | dd of=/dev/sda

イメージが分割されている場合は、代わりに以下を使用してください:

# cat /path/to/backup.img.gz* | gunzip -c | dd of=/dev/sda

MBR のバックアップと復元

ディスクに変更を加える前に、ドライブのパーティションテーブルとパーティションスキームをバックアップしておくと良いでしょう。また、同じパーティションレイアウトを複数のドライブにコピーするためにバックアップを使うこともできます。

MBR はディスクの先頭 512 バイトに格納されています。MBR は4つの部分から成ります:

  1. 始めの 440 バイトにはブートストラップコード (ブートローダ) が含まれています。
  2. 次の 6 バイトにはディスクのシグネチャが含まれています。
  3. 次の 64 バイトにはパーティションテーブルが含まれています (各16バイトの4つのエントリ、各プライマリパーティションに1つのエントリ)。
  4. 最後の 2 バイトにはブートシグネチャが含まれています。

MBR を mbr_file.img として保存するには:

# dd if=/dev/sdX of=/path/to/mbr_file.img bs=512 count=1

完全な dd ディスクイメージから MBR を取り出すこともできます:

# dd if=/path/to/disk.img of=/path/to/mbr_file.img bs=512 count=1

バックアップから MBR を復元するには (注意。このコマンドは既存のパーティションテーブルを破壊し、ディスク上のすべてのデータにアクセスできなくなります):

# dd if=/path/to/mbr_file.img of=/dev/sdX bs=512 count=1
警告: 一致しないパーティションテーブルを使って MBR を復元すると、データを読み出せなくなり、ほぼ復元不可能になります。ブートローダを再インストールしたいだけならば、ブートローダは DOS 互換領域も実装しているので、そのブートローダの関連するページを見てください: GRUBSyslinux

ブートローダを復元したいだけで、プライマリパーティションテーブルのエントリに興味はないならば、単に MBR の先頭 440 バイトを復元すれば良いだけです:

# dd if=/path/to/mbr_file.img of=/dev/sdX bs=440 count=1

パーティションテーブルだけを復元するには、以下のコマンドを使う必要があります:

# dd if=/path/to/mbr_file.img of=/dev/sdX bs=1 skip=446 count=64

ブートローダーの削除

MBR ブートスラップコードを消去するには(別のオペレーティングシステムを完全に再インストールする必要がある場合に役立つ場合があります)、最初の440バイトのみをゼロにする必要があります:

# dd if=/dev/zero of=/dev/sdX bs=440 count=1

ディスク関連や他の使用場面

既にお気づきの方もいらっしゃるかもしれませんが、dd(1) コアユーティリティは他のユーティリティと比較して かなり異なる コマンドラインのシンタックスを持っています。さらに、他のコモディティユーティリティにはないユニークな機能 をサポートしていますが、特定のシナリオに適用すると、あまり理想的でないpotential error-prone デフォルト動作 (時には、できないこと) がいくつも存在します。そのため、ユーザーは dd コアユーティリティの代わりに、ある面ではより優れた代替品を使いたいと思うかもしれません。

そうは言っても、ddcore utility であり、Arch や他の多くのシステムにデフォルトでインストールされているため、代替ユーティリティやより専門化されたユーティリティよりも好ましいことに注意する必要があります。システムに新しいパッケージをインストールするのは不便です。

上記で説明した 2 つの側面をカバーするために、このセクションでは、他の汎用ユーティリティではほとんど見られない dd(1) コア ユーティリティの機能を、Pacman/比較表 の記事に似た形式で要約することに専念します。ただし、サンプルの量は、dd のこれらの機能を調べるのに十分な量 (ヒント:ie または To 節で示されています) にできる限り少なく、単純に削減されています。サブセクションの下のボックス)、実践または疑似コードのいずれかにおいてです.

ノート: この専用セクションを適切な長さに保つために、代替ユーティリティの比較には、公式リポジトリにあるパッケージのみが含まれています。この場合、言及されている他のユーティリティよりも明らかな利点があり、必要に応じて詳細が記載されています。
その他の代替ユーティリティについては、coreutils#dd の代替 を参照して下さい。

バイナリファイルにブロック単位のパッチをインプレースに適用する

自動シェルスクリプトで機能が限定されたバイナリファイルパッチャーとして dd を使用することは珍しいことではありません。これは、書き込み前に指定されたオフセットによって出力ファイルを seek することができ、ブロックすることができるためです。 conv=notrunc オプションを追加して、出力ファイルにブロック単位 (または bs=1 の場合はバイト y バイト) でインプレースパッチを適用します。

たとえば、cpio(5) § Portable ASCII Format アーカイブ内の最初のメンバーのタイムスタンプ部分を変更するには、ファイルの 49 番目のバイトから始まります (または、次の場合は 0x30 のオフセットで始まります)。16 進表記を好む場合):

$ touch a-randomly-chosen-file
$ bsdtar -cf example-modify-ts.cpio --format odc -- a-randomly-chosen-file
$ printf '%011o' "$(date -d "2019-12-21 00:00:00" +%s)" | dd conv=notrunc of=example-modify-ts.cpio seek=48 oflag=seek_bytes
ノート: 現在文書化されていない seek_bytes 出力フラグ は、出力への write(2) を開始する前にブロックではなくバイトのオフセットで出力をシークするために上記に追加されています。
ヒント: コマンドライン入力の 16 進表記からバイト ストリームを出力するには、basenc(1) § base16 および/または printf(1) を使用します。
ヒント: この機能では、dd の代わりに、シェルが開いたファイルディスクリプタに対して lseek(2) を呼び出すことをサポートするシェルを使用することを検討することができます。:
  • dd の入力ファイルは splice(2) システムコールを利用するプログラムと接続されたパイプであり、ユーザはより良いパフォーマンスのために dd の不必要なユーザ空間 I/O を避けたいと考えています。
  • または、シェルスクリプトのループ内で頻繁に fork(2) が発生するのを避け、パフォーマンスペナルティを下げたい。
その場合、まずそのシェルにファイルディスクリプタを開かせ、そのファイルディスクリプタに対してシーク操作を行い、splice(2) システムコールを使う対応するユーティリティの出力端としてこのファイルディスクリプタを割り当てる必要があります(あるいはzshmodules(1) § sysseek のようにフォークしないシェル内蔵コマンドもあります):
$ zsh
$ local +xr openToWriteFD
$ zmodload zsh/system
$ sysopen -wo cloexec -u openToWriteFD example-modify-ts.cpio
$ sysseek -u $openToWriteFD 48
$ printf '%011o' "$(date -d "2019-12-21 00:00:00" +%s)" >&${openToWriteFD}
警告: オフセットを使用して書き込む必要があるプログラムが実際に splice(2) を使用していることを確認できない場合は、このアプローチの使用を避けてください (これは、プログラムが出力に対していかなる種類のシークや切り捨ても実行しないことを意味します)。一部のプログラムは、この動作がコマンド ラインフラグで指定されていない場合でも、入力/出力ファイル記述子を自動的にシーク/切り捨てることがあります。これにより、シェルの lseek(3) 呼び出しが無効になったり、開いているファイル記述子が予期せず切り詰められたりすることがあります。

VFAT ファイルシステムイメージのボリュームラベルを表示する

ヒント: この特定のシナリオでは、より現実的な選択肢は file です。

ファイルシステム VFAT のボリュームラベル イメージファイルを読み取るには、ASCII スペースが埋め込まれた全長 11 バイトで、オフセットは 0x047 です。:

$ truncate -s 33M empty-hole.img
$ fatlabel empty-hole.img LabelMe
$ dd iflag=skip_bytes,count_bytes count=11 skip=$((0x047)) if=empty-hole.img | sed -e 's% *$%%'
ノート: 両方の入力フラグは現在文書化されていません:
  • 以前の skip_bytes は、入力ファイルから read(2) を開始する前に、ブロック数ではなくバイト数でオフセットしてシーク (シークできない入力の場合は skip) するように dd に指示しました。
  • count_bytes では、ブロック数ではなく、入力ファイルからコピーするブロックの総量を バイト で指定することができます。このオプションを指定しても部分的な read(2) の対象となる可能性があるので混乱するかもしれませんが、この挙動をより理解するために input block count の小数値と考えるようにします。
ヒント: 指定された長さ内で入力 (オフセット付き) から出力にデータを転送するには、シェル スクリプトでは、代わりに範囲表記を使用する代替手段として curl(1) § r, を考慮することもできます。
ノート: curl は、入力ファイルがデバイス/パイプである場合のシーク/スキップをサポートしません。別の代替手段 socat(1) は、入力ファイルに対するこれらの操作をサポートします (ブロックデバイスを含む、パイプを除く) 文字デバイス) ですが、curl ほどコモディティ化されていません。:
$ socat -u -,seek=$((0x047)),readbytes=11 - < empty-hole.img | sed -e 's% *$%%'

パイプで繋がれたコマンド間で sponge する

ヒント: タイトルですでに述べたように、この特定のシナリオでの実際的な選択肢は ${TMPDIR:-/tmp} への書き込みによるアトミック書き込みをサポートする sponge(1) です

次の例では、出力側のブロックが予想より長くなった場合に、入力側で不必要に長く続く TCP 接続を避けるために、2 つのコマンドの間に dd を挿入し、出力ブロックサイズは入力よりも確実に大きく、それでも使用可能なメモリよりはかなり小さいものにすることができます。

$ curl -qgsfL http://example.org/mirrors/ftp.archlinux.org/mirrored.md5deep | dd ibs=128k obs=200M | poor-mirroring-script-that-perform-mirroring-on-input-paths-line-by-line-wo-buffer-entire-list-first
警告: dd はコピー操作全体を開始する前に出力ファイルを切り詰めるため、これを sponge(1) の一般的な代替手段として考慮しないでください。

サイズの制限付きでデータを転送する

データストリーミングのシェルスクリプトで dd を使用すると、パイプコマンドで消費されるデータの合計長を制限することができるのは一般的です。例えば、ustar ヘッダブロック (tar(5) § POSIX ustar Archives) をシェルスクリプトの機能を使ってストリーミング方式で検査する場合です:

ノート: count オプションの引数にある B サフィックスは GNU coreutils v9.1 の 新しく導入された 機能で、 dd#VFAT ファイルシステムイメージのボリュームラベルを表示する と同じ効果を持っている。 この機能は、count=256kのように、dd がバイトではなく262144個の入力ブロックをコピーすることを示すオプションと混同される可能性があります。
hexdump-field() {
  set -o pipefail
  printf '%s[%d]:\n' $1 $2
  dd count=${2}B status=none | hexdump -e $2'/1 "%3.2x"' -e '" | " '$2'/1 "%_p" "\n"'
}

inspect-tar-header-block() {
  local -a hdrstack=(
    name 100
    mode 8
    uid 8
    gid 8
    size 12
    mtime 12
    checksum 8
    typeflag 1
    linkname 100
    magic 6
    version 2
    uname 32
    gname 32
    devmajor 8
    devminor 8
    prefix 155
    pad 12
  )
  set - ${hdrstack[@]}
  while test $# -gt 0; do
    hexdump-field $1 $2 || return
    shift 2
  done
}
$ bsdtar -cf - /dev/tty /dev/null 2>&- | dd count=1 skip=1 status=none | inspect-tar-header-block
ヒント: 指定された長さ内で入力から出力にデータをストリーミングするには という代替案は、splice(2) システムコールをサポートする pv(1) § S, です。
ノート: もう 1 つの代替候補は head(1) § c ですが、GNU coreutils 以外の実装 と glibc は消費する可能性があります要求されたデータよりも多くのデータ] が発生し、ストリーミングシェルスクリプトでデータの不整合の問題が発生します。
ヒント: 上記の機能グリッドに加えて、入力ファイルがストリーミング前に特定のオフセットによって lseek(2) され、dd の出力端がプログラムに接続されたパイプである場合は、splice(2) の場合、代わりに次の使用を検討できます。 次の bash の例のように pv(1) § S, (前述) を実行します (ファイル記述子が ls -l /proc によってシェルに割り当てられていないと仮定します) 最初は bash の /self/fd
$ bash
$ exec 9<dummy-but-rather-large.img
$ xxd -g 0 -l 0 -s $((0x47ffff)) <&9
$ pv -qSs 104857601200 <&9 | program-that-process-load-of-data-but-does-not-limit-read-length-as-desired-nor-support-offset-read
$ exec 9<&-
ノート: POSIX および一部の非 GNU 実装とは互換性がありませんが、上記の例の xxd(1) § s の使用を、count=0 と組み合わせた dd に置き換えることは可能です。および skip オプション coreutils テストスイートの例

ブータブルなディスクイメージをブロックデバイスに書き込み、任意で進捗情報を表示する

その場合に最も適合性が低い可能性がある dd を含むコモディティ ユーティリティの例については、USB インストールメディア#基本的なコマンドラインユーティリティを使う を参照してください。

ヒント: ファイルの内容をブロックデバイスに書き込む (進行状況インジケーター付き) という代替案として、dd_rescue(1) § W が推奨されます。デバイス上の古いバージョンのイメージを新しいバージョンで上書きする場合、不要な書き込みを回避できます。

トラブルシューティング

部分読み取り: コピーされたデータは要求されたデータよりも小さい

[3] のように、現時点で完全な入力ブロックが利用できない場合、dd で作成されたファイルは要求されたサイズよりも小さくなる可能性があります。per ドキュメント:

さらに、データ変換する conv 被演算子 (つまり、この Wiki 記事のようなオプション) が指定されていない場合、入力は読み取られるとすぐに出力にコピーされます。ブロックサイズより小さいです。

Linuxでは、read(2) システムコールは pipe(7) から読むとき、または /dev/urandom/dev/random などのデバイスファイルを読むときに早く戻ることがあります (つまり、部分読み) (例えば、基礎となるカーネルデバイスドライバーのハードコーディングされた制限 またはエントロピーが不十分です) ここで n は出力にコピーする入力ブロックの最大数 (潜在的な部分) を制限します。

可能性はありますが、保証はできません。dd がそのような種類の問題について警告する可能性があります。

dd: warning: partial read (X bytes); suggest iflag=fullblock

解決策は、警告にあるように、入力ファイルオプションに加えて iflag=fullblock オプションを dd コマンドに追加することです。たとえば、合計長が 40 MB のランダム データで満たされた新しいファイルを作成するには、次のようにします。

$ dd if=/dev/urandom of=new-file-filled-by-urandom.bin bs=40M count=1 iflag=fullblock
ノート: パイプや特殊なデバイスのファイルから読み込む際に、count=n オプションを指定して、ファイルの一部を固定長でコピーすることが推奨されます、また、デバイスの一部ファイル完全消去 する場合は、iflag=fullblock オプションを追加してdd コマンドで行うことを常に強くお勧めします。

パイプから読み込む場合、iflag=fullblock代替案 として、bslinux/limits.h で定義されている PIPE_BUF 定数に制限して pipe(7) の I/O を原子化します。例えば、全長5メガバイトのランダムな英数字で埋め尽くされたテキストファイルを用意する場合、以下のようになります:

$ LC_ALL=C tr -dc '[:alnum:]' </dev/urandom | dd of=passtext-5m.txt bs=4k count=1280

出力ファイルはパイプではないため、(入力) パイプと (出力) ディスク上のファイル。たとえば、出力ファイルのより効率的なブロック サイズを設定するには、次のようにします。

$ LC_ALL=C tr -dc '[:alnum:]' </dev/urandom | dd of=passtext-5m.txt ibs=4k obs=64k count=1280
ヒント: 状況によっては、出力ブロックサイズを入力ブロックサイズと同じ値に保つだけで、PIPE_BUF 定数で定義された値がすでに最適である場合があります。

総転送バイト数の読み出しが間違っている

以下の概念実証のように、出力への書き込み時にエラーが発生した場合 (例えば、SIGPIPE、欠陥のある媒体、または誤ってターゲットネットワークブロックデバイスを切断したことによる 部分書き込み)、読み出された総転送バイト数は実際よりも大きくなる可能性があります:第2の dd は明らかに512200バイト以上を読みませんが、第1の dd インスタンスはまだ不正確なバイト数512400バイトを報告します:

$ yes 'x' | dd bs=4096 count=512400B | dd ibs=1 count=512200 status=none >/dev/null
125+1 records in
125+1 records out
512400 bytes (512 kB, 500 KiB) copied, 10.7137 s, 47.8 kB/s

上記の PoC のように中断された転送を再開する場合、"+" 記号の前の数字で示されるように、既にコピーされた全出力ブロックの数の読み出しのみに依存することをお勧めします。

ノート: iflag=fullblock オプションを追加しても、部分I/Oブロック数が1より大きい場合は、部分 I/O が2回以上発生したことになります。 この場合、確実に転送を再開するために、次のことをお勧めします:
  • 潜在的な欠陥媒体の部分読み出しに柔軟に対処するために、代わりに ddrescue を使用して転送を再実行する。
  • ネットワーク接続が悪い状態で nbd に書き込む場合、dd_rescue(1) を使って直接 I/O で転送を再実行する。
  • 欠陥のある媒体への書き込みを避けることができます。

参照