1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Ansibleが理解できない理由はLinuxにあった【Shell編】第2回:なぜ結果が消えるのか(Redirect / Pipe)

1
Last updated at Posted at 2026-04-06

📚 連載:Ansibleが理解できない理由はLinuxにあった【Shell編】第2回:なぜ結果が消えるのか(Redirect / Pipe)

Shellの仕組みからAnsibleを理解するシリーズです。

① なぜShellを理解しないとAnsibleは使えないのか
② なぜAnsibleで出力が取得できないのか
③ なぜ結果が消えるのか
④ なぜgrepで見つからないのか
⑤ なぜ正規表現で壊れるのか
⑥ なぜ環境が違うのか
⑦ なぜ条件分岐が失敗するのか
⑧ なぜループがうまく動かないのか
⑨ なぜ途中で処理が止まるのか
⑩ なぜ変数が意図通りに展開されないのか
⑪ なぜAnsibleの挙動が読めるようになるのか


🗺️ 初めての方・シリーズの全体像を知りたい方はこちら

本記事は、OSの仕組みからAnsible設計までを繋ぐ連載シリーズの一部です。
「どこから読み始めればいいか」あるいは、「OS/Shell/Ansible編の関係性」 について把握されたい場合は、以下の統合ガイドで整理しています。

Ansibleが理解できない理由はLinuxにあった|統合ガイド


📑 【Shell編】全体のまとめはこちら
Ansibleが理解できない理由はLinuxにあった【Shell編】まとめ


📑 連載の移動
前の記事:【Shell編】第1回 | 次の記事:【Shell編】第3回


📋 目次

  1. 前回の振り返り(第1回)
  2. 逆引き辞典との連動
  3. Shellのストリーム構造:データと転送先の分離
  4. なぜ消えるのか:転送先決定の「2つの判定ステップ」
  5. 状態からの逆引き:転送先の特定
  6. 【実機検証】データの転送と消失:Ansibleに届かない「行先」の特定
  7. まとめ:出力消失を特定する「調査の原則」
  8. 次回予告
  9. 連載一覧:Ansibleが理解できない理由はLinuxにあった【Shell編】

※本記事の位置とシリーズ全体の関係を先に確認します。


:map: シリーズ全体構造(学習 × 問題解決)

本シリーズは
「理解(各記事)」と「問題解決(逆引き辞典)」を組み合わせて
スキルを身につける構成になっています。

この図は、どこから学び、どこに進めばよいかを示した“ロードマップ”です。


📍 現在の位置


現在はこの図の「Shell編の第2回」になります


↑ 目次に戻る


📍 はじめに:この記事のスタンス

第1回では、OSには「1番(stdout)」と「2番(stderr)」という2つの独立した出口があることを整理しました。しかし、出口の役割を把握していても、依然として「実行結果が空になる」現象は発生します。

  • パイプ( | )を繋ぐと、本来表示されるはずのログが消える

  • リダイレクト( > )を記述すると、Ansibleの register 変数が空になる

  • 手元でのコマンド実行結果と、Ansibleで取得した変数の中身が一致しない

これらの原因は、出口の先で行われる 「データ転送(流路の切り替え)」 にあります。


⚠️ 注意事項

この記事の目的は、ファイル記述子の深層理論を解説することではありません。
Ansibleで出力が「消えた」と感じたとき、以下の状態を即座に特定することを目指します。

  • 「OSがデータをどのプロセス、あるいはどのファイルへ転送したのか」

「出力はされたが、Ansibleへ届く手前で別の場所へ送られた」という物理的な挙動を把握することで、実務上の出力制御を理解します。


1. 前回の振り返り(第1回)

前回は、出力には2つの独立した出口があることを学びました。

  • 1番(stdout):標準出力

  • 2番(stderr):標準エラー出力

今回は、出口から出たデータが 「パイプ( | )」「リダイレクト( > )」 によって、どのように転送先が上書きされるのか。その判定ロジックとAnsibleへの影響を解説します。


↑ 目次に戻る


2. 逆引き辞典との連動

具体的なエラー名から原因を特定したい場合は、以下の逆引き辞典を活用してください。

【保存版】Ansibleよくあるエラー一覧と原因まとめ(Shell編)

  • まず「逆引き辞典」で該当ステップを特定する
  • 次に「本編(各連載記事)」で仕組みを理解する

このサイクルが、OS編から続くトラブル解決の最短ルートです。


↑ 目次に戻る


3. Shellのストリーム構造:データと転送先の分離

OS(Shell)において、コマンドが出力したデータは内部的な「転送先設定(ファイル記述子)」によって制御されます。Ansibleはこの仕組みに依存してデータを取得しています。

転送先 標準の出力先 実務上の指定方法
呼び出し元(Ansible) デフォルトの出力先 特になし(デフォルト)
他プロセス(Pipe) 後続のコマンドへ渡す |
ファイル(Redirect) 永続的に保存する > >> /dev/null

「出力が取得できない」事象は、実際には 「OSによって別の転送先にデータが送られている」 という状態を示しています。


↑ 目次に戻る


4. なぜ消えるのか:転送先決定の「2つの判定ステップ」

OSは出力の転送先を以下の順序で判定します。途中のステップで転送先が確定した場合、そのデータはAnsible(呼び出し元)には到達しません。


転送先判定の仕様

ステップ 判定内容 到達しない理由
Step 1: Pipe 他プロセスに渡しているか 出力が次段のコマンドの入力として消費されるため
Step 2: Redirect ファイルに書き込んでいるか 出力先がターミナルからファイルへ置き換わるため

【ストリーム転送フロー】


結論:取得失敗の本質

データが消失しているのではなく、OSによる流路制御(転送)によって、Ansibleへの経路から外れていることが原因です。


↑ 目次に戻る


5. 状態からの逆引き:転送先の特定

Ansibleの実行結果(register 変数)の状態を確認することで、OSがどのステップを通過したかを特定できます。


観測対象と判定の目安

観測対象 状態 判定されるStep
result.stdout が空 出力が届いていない Step1 または Step2
最終コマンドの結果のみ存在 中間処理のログが欠損 Step1(Pipe)
ファイルに内容が存在 stdoutが空 Step2(Redirect)
/dev/null を指定 完全に消失 Step2(Redirect)

OSがどの判定を優先したかを切り分けることで、期待したデータが取得できない原因を物理的に特定可能です。


↑ 目次に戻る


6. 【実機検証】データの転送と消失:Ansibleに届かない「行先」の特定

セクション4で解説した「転送先判定(Pipe / Redirect)」が、実際のAnsible実行においてどのようにデータを遮断するのか。その物理的な挙動を確認します。

6-1. 【検証1】リダイレクトによる「stdout」の空化(Step 2)

コマンドの実行結果をファイルへ書き込んだ際、Ansibleの stdout 変数がどのような状態になるかを観測します。

① 検証手順(リモートノード側)

標準出力を持つコマンドを実行し、リダイレクトを用いてその行先を変更します。

# 現在時刻をファイルに書き込む
[ansibleuser@localhost ~]$ date > /tmp/date_result.txt

※この時、ターミナル上には何も表示されません。これをAnsible経由で実行し、register 変数の中身を確認します。

② Ansibleによる実行テスト

実行するPlaybook (case1_redirect.yml)

---
- name: 検証1 リダイレクトによるデータの行先
  hosts: test_servers
  gather_facts: false
  tasks:
    - name: ファイルへリダイレクトして実行
      ansible.builtin.shell: "date > /tmp/date_result.txt"
      register: res_redirect

    - name: 変数の中身を確認
      ansible.builtin.debug:
        msg: "STDOUTの中身: {{ res_redirect.stdout }}"

実行コマンド

ansible-playbook -i inventory.ini case1_redirect.yml

③ 検証結果

(ansible) [root@localhost workspace]# ansible-playbook -i inventory.ini case1_redirect.yml

PLAY [検証1 リダイレクトによるデータの行先] *************************************************************************************************************************************************

TASK [ファイルへリダイレクトして実行] *******************************************************************************************************************************************************
changed: [192.168.1.21]

TASK [変数の中身を確認] *********************************************************************************************************************************************************************
ok: [192.168.1.21] => {
    "msg": "STDOUTの中身: "
}

PLAY RECAP **********************************************************************************************************************************************************************************
192.168.1.21               : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

ログの読み解きと考察

  • 現象: タスクは正常終了し、リモートノード側でファイルへの書き込みも完了していますが、res_redirect.stdout は完全に空となっています。

  • 理由: OSレベルで stdout(ファイル記述子 1)の出力先が「呼び出し元(Ansible)」から「ファイルシステム」へ切り替わったためです。Ansibleは標準出力から流れてくるデータをキャプチャしているため、出力先がファイルに固定された場合、その中身を保持することはできません。

テスト結果のまとめ:

リダイレクトを用いた際にAnsibleで内容を取得できない原因は、OSがデータの転送先をファイルへ固定し、Ansible(呼び出し元)への流路を遮断したためです。


6-2. 【検証2】パイプラインによる中間データの「消費」(Step 1)

複数のコマンドを繋いだ際、前段のコマンドが出力したデータがAnsibleに届かない現象を確認します。

① 検証手順(OS上での挙動確認)

echo で出力した文字列を sed で加工します。

[ansibleuser@localhost ~]$ echo "Raw_Data" | sed 's/Raw/Processed/'
Processed_Data

※この時、最終的な加工結果のみが表示されます。Ansibleが保持しているデータが「誰のものか」を検証します。

② Ansibleによる実行テスト

実行するPlaybook (case2_pipe_flow.yml)

---
- name: 検証2 パイプラインにおけるデータの消費
  hosts: test_servers
  gather_facts: false
  tasks:
    - name: パイプを含むコマンドの実行
      ansible.builtin.shell: "echo 'Raw_Data' | sed 's/Raw/Processed/'"
      register: res_pipe

    - name: 変数の中身を確認
      ansible.builtin.debug:
        msg: "取得されたデータ: {{ res_pipe.stdout }}"

実行コマンド

ansible-playbook -i inventory.ini case2_pipe_flow.yml

③ 検証結果

(ansible) [root@localhost workspace]# ansible-playbook -i inventory.ini case2_pipe_flow.yml

PLAY [検証2 パイプラインにおけるデータの消費] ***********************************************************************************************************************************************

TASK [パイプを含むコマンドの実行] ***********************************************************************************************************************************************************
changed: [192.168.1.21]

TASK [変数の中身を確認] *********************************************************************************************************************************************************************
ok: [192.168.1.21] => {
    "msg": "取得されたデータ: Processed_Data"
}

PLAY RECAP **********************************************************************************************************************************************************************************
192.168.1.21               : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

ログの読み解きと考察

  • 現象res_pipe.stdout に格納されたのは Processed_Data のみであり、前段の echo が出力した Raw_Data は含まれていません。

  • 理由Raw_Data はパイプ(Step 1)によって次段の sed コマンドの標準入力へと転送され、そのプロセス内で消費されたためです。Ansibleの register 変数に届くのは、常にパイプラインの最終段が出力したストリームのみとなります。

テスト結果のまとめ:

途中の出力が欠落する原因は、前段の出力がOSによって次段プロセスの入力へと転送され、Ansibleへの流路から外れたためです。


↑ 目次に戻る


7. まとめ:出力消失を特定する「調査の原則」

Ansibleで期待した出力が得られない場合は、以下のフローで確認を行います。

【調査手順】

1. Pipe(Step 1)の確認
   → 「|」が使われていないか。
   → 中間出力は後続プロセスに渡され、Ansibleの手前で消費される。

2. Redirect(Step 2)の確認
   → 「>」「>>」「2>」が使われていないか。
   → 出力先がターミナルからファイルへ切り替わる。

3. 最終到達点の特定
   → 最終的にデータはどこ(stdout / stderr / ファイル / /dev/null)へ送られたか。

調査の視点

出力の消失は、エラーやバグではなくOSの正常な挙動(転送)の結果です。
「どこに出ているか」ではなく、「OSがどこへ転送したか」という視点でコマンドラインを分解してください。

  • |> の有無から通過したStepを特定する。

  • 実行後の状態(変数の空き具合、ファイルの有無)からOSの判定結果を逆算する。

この原則に沿って確認すれば、データが途絶えた箇所を物理的に特定できます。

出力問題は、出口(第1回)」と「転送(第2回) の組み合わせによって、その原因がすべて整理可能です。


↑ 目次に戻る


8. 次回予告

ここまで、出力の「出口」と「転送」の仕組みを整理しました。

しかし、実務では次のような事象に直面することがあります。

「ファイルにデータは存在するのに、grepでヒットしない」
「プロンプトの入力待ち状態で、Ansibleのタスクが停止(ハングアップ)する」

これらの原因は、出力(stdout)ではなく「入力(stdin)」の扱いにあります。

次回:

【Shell編】第3回:なぜgrepで見つからないのか(stdin)

「入力」の仕組みを理解することで、Shellにおけるデータの流れを完結させます。


↑ 目次に戻る


📑 連載の移動
前の記事:【Shell編】第1回 | 次の記事:【Shell編】第3回


📑 【Shell編】全体のまとめはこちら
Ansibleが理解できない理由はLinuxにあった【Shell編】まとめ


🗺️ 初めての方・シリーズの全体像を知りたい方はこちら

本記事は、OSの仕組みからAnsible設計までを繋ぐ連載シリーズの一部です。
「どこから読み始めればいいか」あるいは、「OS/Shell/Ansible編の関係性」 について把握されたい場合は、以下の統合ガイドで整理しています。

Ansibleが理解できない理由はLinuxにあった|統合ガイド


9. 連載一覧:Ansibleが理解できない理由はLinuxにあった【Shell編】

回数とタイトル 内容(概要)
【Shell編】第0回:なぜShellを理解しないとAnsibleは使えないのか AnsibleはShellを通してコマンドを実行している。Ansible → SSH → Shell → Linux の構造を理解し、なぜShell理解が必須なのかを整理する。
【Shell編】第1回:なぜAnsibleで出力が取得できないのか Ansibleでregisterが空になる・エラーが見えない原因はstdout / stderrの違いにある。Shellの出力構造を理解することで原因を特定できる。
【Shell編】第2回:なぜ結果が消えるのか Ansibleで実行結果が見えなくなる原因はパイプ・リダイレクトによる出力先の変化にある。どこに出力が流れたのかを追うことで原因を特定できる。
【Shell編】第3回:なぜgrepで見つからないのか Ansibleでgrepがヒットしない原因は検索対象ではなく入力(stdin)の問題にある。Shellの入力(ストリーム)構造を理解することで原因を特定できる。
【Shell編】第4回:なぜ正規表現で壊れるのか Ansibleで検索や置換が壊れる原因は正規表現の評価ルールにある。文字列ではなくルールとして解釈される仕組みを理解し、リテラルの境界を学ぶ。
【Shell編】第5回:なぜ環境が違うのか 手動では動くのにAnsibleで失敗する原因は実行環境(PATH・環境変数)の差分にある。Shellの実行コンテキストの違いを理解し、環境を制御する。
【Shell編】第6回:なぜ条件分岐が失敗するのか Ansibleのwhen条件が意図通りに動かない原因はexit codeにある。Shellの終了ステータスの判定ロジックを理解することで、正しく条件を組める。
【Shell編】第7回:なぜループがうまく動かないのか Ansibleで繰り返し処理が期待通り動かない原因はShellのループと入力・サブシェルの干渉にある。データの扱い方を理解し、ループを安定させる。
【Shell編】第8回:なぜ途中で処理が止まるのか Ansible実行中に意図せず処理が止まる原因はShellのエラーハンドリング(set -e 等)にある。エラー伝播の仕組みを理解し、停止条件を制御する。
【Shell編】第9回:なぜ変数が意図通りに展開されないのか Ansibleで変数が空になる・壊れる原因はShellのクォートと展開順序にある。値の保護と展開のルールを理解し、安定したコマンドを記述する。
【Shell編】第10回:なぜ値が分割されてしまうのか スペースや改行で意図せず値が壊れる原因はShellの単語分割(word splitting)にある。IFSなどの内部処理の本質を理解し、データの整合性を守る。
【Shell編】第11回:なぜAnsibleの挙動が読めるようになるのか これまでの知識を統合し、AnsibleのエラーをShellの実行プロセスから逆算して分解できるようになる。実務で使える“読み方”を完成させる。

↑ 目次に戻る


1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?