「Dd」の版間の差分
(→ディスク関連や他の使用場面: 翻訳) |
(→ディスク関連や他の使用場面: リンクを修正) |
||
152行目: | 152行目: | ||
そうは言っても、''dd'' は [[coreutils|core utility]] であり、Arch や他の多くのシステムにデフォルトでインストールされているため、代替ユーティリティやより専門化されたユーティリティよりも好ましいことに注意する必要があります。システムに新しいパッケージをインストールするのは不便です。 |
そうは言っても、''dd'' は [[coreutils|core utility]] であり、Arch や他の多くのシステムにデフォルトでインストールされているため、代替ユーティリティやより専門化されたユーティリティよりも好ましいことに注意する必要があります。システムに新しいパッケージをインストールするのは不便です。 |
||
− | 上記で説明した 2 つの側面をカバーするために、このセクションでは、他の汎用ユーティリティではほとんど見られない {{man|1|dd}} コア ユーティリティの機能を、[[ |
+ | 上記で説明した 2 つの側面をカバーするために、このセクションでは、他の汎用ユーティリティではほとんど見られない {{man|1|dd}} コア ユーティリティの機能を、[[Pacman/比較表]] の記事に似た形式で要約することに専念します。ただし、サンプルの量は、''dd'' のこれらの機能を調べるのに十分な量 (''ヒント:'' の ''ie'' または ''To'' 節で示されています) にできる限り少なく、単純に削減されています。サブセクションの下のボックス)、実践または疑似コードのいずれかにおいてです. |
− | {{note|この専用セクションを適切な長さに保つために、代替ユーティリティの比較には、公式リポジトリにあるパッケージのみが含まれています。この場合、言及されている他のユーティリティよりも明らかな利点があり、必要に応じて詳細が記載されています。<br>その他の代替ユーティリティについては、[[coreutils#dd の代替 |
+ | {{note|この専用セクションを適切な長さに保つために、代替ユーティリティの比較には、公式リポジトリにあるパッケージのみが含まれています。この場合、言及されている他のユーティリティよりも明らかな利点があり、必要に応じて詳細が記載されています。<br>その他の代替ユーティリティについては、[[coreutils#dd の代替]] を参照して下さい。}} |
=== バイナリファイルにブロック単位のパッチをインプレースに適用する === |
=== バイナリファイルにブロック単位のパッチをインプレースに適用する === |
2023年5月19日 (金) 18:21時点における版
dd はファイルの変換とコピーを主な目的とする コアユーティリティ です。
cp と同様にデフォルトでは dd はファイルのビットごとのコピーを作成しますが、低レベルの I/O フロー制御機能を備えています。
詳細は、dd(1) またはフルドキュメントを参照してください。
インストール
dd は GNU coreutils の一部です。このパッケージ内の他のユーティリティについては、Core utilities を参照してください。
ディスクの複製と復元
dd コマンドはシンプルでありながら多機能で強力なツールです。ファイルシステムの種類や OS に関係なく、コピー元からコピー先へブロック単位でコピーすることができます。ライブ CD のようなライブ環境から dd を使用するのが便利です。
パーティションの複製
物理ディスク /dev/sda
のパーティション 1 から、物理ディスク /dev/sdb
のパーティション 1 へ:
# dd if=/dev/sda1 of=/dev/sdb1 bs=64K conv=noerror,sync status=progress
ハードディスク全体の複製
物理ディスク /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
は、操作がいつ完了するかを推測するために使用できる転送統計を表示します。
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 ブロック全体をめちゃくちゃにします。
パーティションテーブルのバックアップ
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
{{Tip|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つの部分から成ります:
- 始めの 440 バイトにはブートストラップコード (ブートローダ) が含まれています。
- 次の 6 バイトにはディスクのシグネチャが含まれています。
- 次の 64 バイトにはパーティションテーブルが含まれています (各16バイトの4つのエントリ、各プライマリパーティションに1つのエントリ)。
- 最後の 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 の先頭 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 コアユーティリティの代わりに、ある面ではより優れた代替品を使いたいと思うかもしれません。
そうは言っても、dd は core utility であり、Arch や他の多くのシステムにデフォルトでインストールされているため、代替ユーティリティやより専門化されたユーティリティよりも好ましいことに注意する必要があります。システムに新しいパッケージをインストールするのは不便です。
上記で説明した 2 つの側面をカバーするために、このセクションでは、他の汎用ユーティリティではほとんど見られない dd(1) コア ユーティリティの機能を、Pacman/比較表 の記事に似た形式で要約することに専念します。ただし、サンプルの量は、dd のこれらの機能を調べるのに十分な量 (ヒント: の ie または To 節で示されています) にできる限り少なく、単純に削減されています。サブセクションの下のボックス)、実践または疑似コードのいずれかにおいてです.
バイナリファイルにブロック単位のパッチをインプレースに適用する
自動シェルスクリプトで機能が限定されたバイナリファイルパッチャーとして 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
VFAT ファイルシステムイメージのボリュームラベルを表示する
ファイルシステム 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% *$%%'
パイプで繋がれたコマンド間で sponge する
次の例では、出力側のブロックが予想より長くなった場合に、入力側で不必要に長く続く 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 を使用すると、パイプコマンドで消費されるデータの合計長を制限することができるのは一般的です。例えば、ustar ヘッダブロック (tar(5) § POSIX ustar Archives) をシェルスクリプトの機能を使ってストリーミング方式で検査する場合です:
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
ブータブルなディスクイメージをブロックデバイスに書き込み、任意で進捗情報を表示する
その場合に最も適合性が低い可能性がある dd を含むコモディティ ユーティリティの例については、USB インストールメディア#基本的なコマンドラインユーティリティを使う を参照してください。
トラブルシューティング
部分読み取り: コピーされたデータは要求されたデータよりも小さい
[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
パイプから読み込む場合、iflag=fullblock
の 代替案 として、bs
を linux/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
総転送バイト数の読み出しが間違っている
以下の概念実証のように、出力への書き込み時にエラーが発生した場合 (例えば、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 のように中断された転送を再開する場合、"+" 記号の前の数字で示されるように、既にコピーされた全出力ブロックの数の読み出しのみに依存することをお勧めします。