1年前LinodeにNixOSをインストールする方法のチュートリアル。
インストールメディアにisoファイルを配置することに関連するほとんどのチュートリアルでは、常に次のものを使用しているようですdd
。「ddは今でも話すことができますか?」彼は私の質問に答えなかった。また、もともとこのチュートリアルで使用されており、ソースからdd
ISOをパイピングしながら、sha256チェックサムを使用してisoを確認するように少し変更しました。tee
curl -L $iso | tee >(dd of=/dev/sda) | sha256sum
しかし、私の考えでは、dd
これは少し冗長であり、実際には次のものよりはるかに遅いです。
curl -L $iso | tee /dev/sda | sha256sum
数ヶ月前、誰かがチュートリアルに従うのを助けて、より簡単な方法を使用するのに問題があることを覚えていました。しかし、先週末に2つの別々のインストールを試みたとき、それはうまく機能しているように見え、速度も非常に高速でした。
この修正はチュートリアルを更新するためにプルリクエストを送信するのに十分安定していますか?
それとも運が良くてうまくいったので、dd
インストールメディアを作成するのは本当に安全で信頼性が高いので、チュートリアルを残す必要がありますか?
答え1
使用する方がdd
安全、高速、信頼性の低下はありません。実際には、2つの追加の失敗のリスクが導入されました。ガイドラインを手動で説明すると、両方のリスクが実際に問題になる可能性が低くなりますが、ガイドラインが自動化されたスクリプトにある場合、両方のリスクは重大なエラーになります。
バグ:競争条件
観察する:
bash-5.0$ echo hello | tee >(sleep 1; echo done); echo next step
hello
next step
bash-5.0$ done
Bashでは、出力プロセスの置換は非同期です。コマンドにプロセス置換が含まれている場合、>(…)
プロセス置換が完了するのを待ちません。
… | tee >(dd of=/dev/sda) | sha256sum
したがって、戻ってくるときdd
。これは、人が反応して他のコマンドを入力するのに十分長く持続する可能性はありませんが、他のコマンドを実行するスクリプト(eject
またはそれ以降)を中断する可能性があります。mount
バグ:欠落しているエラーを検出
すべてがうまく機能する名目上の例から始めましょう。
bash-5.0$ head -c 1m </dev/zero | tee >(cat >/dev/null) | wc -c; echo $?
1048576
0
それでは、データ書き込みコマンドが失敗した場合に何が起こるのかを見てみましょう。
bash-5.0$ head -c 1m </dev/zero | tee >(false) | wc -c; echo $?
8192
0
パイプの終了状態は右側のみに依存するため、コマンドは成功状態を持ちます。データジェネレータがデータプロセッサに接続されている場合、エラーを検出することがデータプロセッサの役割であるという概念です。残念ながら、これはデータ型がデータプロセッサがエラーを検出できる場合にのみ機能しますが、通常はそうではありません。特にここではそうではありません。
tee
接続されたパイプに書き込めない場合は、完全に放棄されますfalse
。データを読んだことがないので、それをfalse
通過する唯一のデータwc -c
は2つですPIPE_BUF
(1つはtee
両方のパイプに書き込み、もう1つはtee
パイプに書き込むwc
だけでパイプに書き込めませんfalse
)。パイプに書き込んでデータを消費するfalse
ことと終了する相対的なタイミングによっては、パスが1つまたは0つしかない場合があります。tee
wc
PIPE_BUF
tee
このオプションを設定するとエラーを検出できますpipefail
。 (この可能性はksh、bash、zshには存在しますが、通常のshにはありません。)
bash-5.0$ set -o pipefail; head -c 1m </dev/zero | tee >(false) | wc -c; echo $?
8192
141
tee
パイプは書き込めないため、シェル状態128 + SIGPIPE値(Linuxの場合13)に対応するSIGPIPEで終了します。このオプションにより、pipefail
パイプライン全体が同じ状態で終了します。
パイプは、プロセス置換のコマンドの失敗をtee
直接反映するのではなく、コマンドの失敗を反映します。代替プロセスのコマンドがすべてのデータを正常に読み取り、正常に処理できなかった場合、エラーは検出されません。
bash-5.0$ head -c 1m </dev/zero | tee >(cat >/dev/null; false) | wc -c; echo $?
1048576
0
wc -c
すべてのデータが処理されました。cat >/dev/null; false
シミュレーションはすべての入力コマンドを正しく処理できませんでした。それにもかかわらず、コマンド状態は成功を示します。
実際の例では、これはデータの終わりにエラーがある場合(たとえば、ターゲットデバイスが画像よりはるかに小さいため)、このエラーが検出されないことを意味します(エラーメッセージを除くdd
)。
シンプルで正しいソリューション
set -o pipefail
curl -L $iso | tee /dev/sda | sha256sum
または間違いなくより簡単です。
curl -L $iso | tee >/dev/sda >(sha256sum)
それ以外の場合、pipefail
2番目のコマンドはcurl
失敗しても成功します。しかし、この失敗は間違いなく間違ったチェックサムをもたらします。
ddの使用に関する一般的な注意
インストールメディアにisoファイルを置く方法を扱うほとんどのチュートリアルは常にddを使用しているようです。これが「ddが今も関係していますか?」という質問に対する答えではない理由です。
まあ、ある程度そうです。具体的には、どの目的があるかについての質問に答えますdd
。dd
この特定のアプローチを使用するときに発生する特定の問題は扱いません。この時間実際、それ自体のためではありませんdd
。
ほとんどのチュートリアルでこれを使用する理由dd
は、ほとんどのチュートリアルがそれを使用するためですdd
。人々はdd
それが実際になぜ使用されているのか理解していなくても、他の場所で使用されているのを見たのでそれを使用します。その構文は他のコマンドとは異なるため、やや神秘的で強力です。しかし、今はdd of=/dev/sda
すべての力がありますが、/dev/sda
何もありませんdd
。それは単に装飾的で壊れやすい執筆方法ですcat >/dev/sda
。