tee isoの内容はddに書き込まれますか、それとも/dev/sdaに直接書き込まれますか?

tee isoの内容はddに書き込まれますか、それとも/dev/sdaに直接書き込まれますか?

1年前LinodeにNixOSをインストールする方法のチュートリアル

インストールメディアにisoファイルを配置することに関連するほとんどのチュートリアルでは、常に次のものを使用しているようですdd「ddは今でも話すことができますか?」彼は私の質問に答えなかった。また、もともとこのチュートリアルで使用されており、ソースからddISOをパイピングしながら、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つしかない場合があります。teewcPIPE_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)

それ以外の場合、pipefail2番目のコマンドはcurl失敗しても成功します。しかし、この失敗は間違いなく間違ったチェックサムをもたらします。

ddの使用に関する一般的な注意

インストールメディアにisoファイルを置く方法を扱うほとんどのチュートリアルは常にddを使用しているようです。これが「ddが今も関係していますか?」という質問に対する答えではない理由です。

まあ、ある程度そうです。具体的には、どの目的があるかについての質問に答えますddddこの特定のアプローチを使用するときに発生する特定の問題は扱いません。この時間実際、それ自体のためではありませんdd

ほとんどのチュートリアルでこれを使用する理由ddは、ほとんどのチュートリアルがそれを使用するためですdd。人々はddそれが実際になぜ使用されているのか理解していなくても、他の場所で使用されているのを見たのでそれを使用します。その構文は他のコマンドとは異なるため、やや神秘的で強力です。しかし、今はdd of=/dev/sdaすべての力がありますが、/dev/sda何もありませんdd。それは単に装飾的で壊れやすい執筆方法ですcat >/dev/sda

関連情報