Linux プロセスの待機

LinuxBeginner
オンラインで実践に進む

はじめに

Linux のプロセスは、プログラムを実行し、タスクを実行するオペレーティングシステムの基本的なコンポーネントです。シェルスクリプトを開発する際には、複数のプロセスを同時に実行し、それらが完了してから後続の操作を続行する必要があることがよくあります。

この実験では、Linux シェルスクリプトにおける wait コマンドについて学びます。この強力なツールを使用すると、親プロセスは、バックグラウンドで実行されている子プロセスが完了するまで実行を一時停止することができます。プロセスの待機技術を習得することで、複数の同時操作を適切に調整する、より効率的なスクリプトを作成することができます。

プロセスの待機を理解することは、システム管理、自動化、および堅牢なシェルスクリプトの開発に不可欠です。バックグラウンドプロセスを起動し、それらの完了を待ち、それらの終了ステータスを処理して、信頼性の高い実行フローを確保する方法を学びます。

Linux プロセスとバックグラウンド実行の理解

このステップでは、Linux のプロセスについて学び、& 演算子を使用してコマンドをバックグラウンドで実行する方法を学びます。

Linux プロセスとは何か?

Linux のプロセスは、実行中のプログラムのインスタンスです。各プロセスには一意のプロセス ID (PID) があり、他のプロセスとは独立して実行されます。ターミナルでコマンドを実行すると、プロセスが起動します。

バックグラウンドでのプロセス実行

通常、ターミナルでコマンドを実行すると、別のコマンドを実行する前にそのコマンドが完了するのを待つ必要があります。ただし、コマンドの末尾にアンパサンド & を追加することで、コマンドをバックグラウンドで実行することができます。

これを試してみましょう。

  1. プロジェクトディレクトリに移動します。

    cd ~/project
  2. 長時間実行されるタスクをシミュレートする簡単なスクリプトを作成します。

    nano long_task.sh
  3. スクリプトに以下の内容を追加します。

    #!/bin/bash
    echo "Starting long task with PID $$"
    sleep 5
    echo "Long task completed"
  4. Ctrl+O を押してファイルを保存し、Enter を押し、Ctrl+X で終了します。

  5. スクリプトを実行可能にします。

    chmod +x long_task.sh
  6. 通常通りスクリプトを実行します。

    ./long_task.sh

    次のような出力が表示されます。

    Starting long task with PID 1234
    Long task completed

    コマンドプロンプトが戻るまで、スクリプトの実行が完了するのを待たなければならないことに注意してください。

  7. 今度はスクリプトをバックグラウンドで実行します。

    ./long_task.sh &

    次のような出力が表示されます。

    [1] 1235
    Starting long task with PID 1235

    [1] はジョブ番号で、1235 は PID です。コマンドプロンプトがすぐに戻ることに注意してください。

  8. 約 5 秒後に、次のような表示がされます。

    Long task completed
    [1]+  Done                    ./long_task.sh

    これは、バックグラウンドプロセスが完了したことを示しています。

コマンドをバックグラウンドで実行すると、シェルはそのコマンドが完了するのを待たずに、さらにコマンドを入力できるようになります。これは、複数のタスクを同時に実行する場合に便利です。

wait コマンドを使用したプロセスの同期

このステップでは、wait コマンドを使用してプロセスを同期する方法を学びます。これにより、親プロセスはバックグラウンドプロセスの完了を待つことができます。

wait コマンドとは何か?

wait コマンドは、シェルスクリプト内で使用され、1 つまたは複数のバックグラウンドプロセスが完了するまでスクリプトの実行を一時停止します。これは、特定のタスクが完了してから後続の操作を行う必要がある場合に特に有用です。

引数なしでの wait コマンドの使用

引数なしで wait コマンドを使用すると、すべてのバックグラウンドプロセスが完了するまで待機します。

これを示すスクリプトを作成しましょう。

  1. プロジェクトディレクトリに移動します。

    cd ~/project
  2. 新しいスクリプトを作成します。

    nano wait_demo.sh
  3. スクリプトに以下の内容を追加します。

    #!/bin/bash
    
    echo "Starting background tasks..."
    
    ## Start two background tasks
    ./long_task.sh &
    ./long_task.sh &
    
    echo "Waiting for all background tasks to complete..."
    wait
    echo "All background tasks have completed!"
  4. Ctrl+O を押してファイルを保存し、Enter を押し、最後に Ctrl+X でエディタを終了します。

  5. スクリプトを実行可能にします。

    chmod +x wait_demo.sh
  6. スクリプトを実行します。

    ./wait_demo.sh

    次のような出力が表示されます。

    Starting background tasks...
    Starting long task with PID 1236
    Starting long task with PID 1237
    Waiting for all background tasks to complete...
    Long task completed
    Long task completed
    All background tasks have completed!

「All background tasks have completed!」というメッセージは、2 つの長時間実行されるタスクが両方とも終了した後にのみ表示されることに注意してください。これは、wait コマンドがすべてのバックグラウンドプロセスが完了するまでスクリプトを一時停止する仕組みを示しています。

特定の PID での wait コマンドの使用

wait コマンドを使用して、特定のプロセスの PID を指定してそのプロセスの完了を待つこともできます。

  1. 別のスクリプトを作成します。

    nano wait_pid_demo.sh
  2. 以下の内容を追加します。

    #!/bin/bash
    
    echo "Starting background tasks..."
    
    ## Start two background tasks and capture their PIDs
    ./long_task.sh &
    pid1=$!
    
    ./long_task.sh &
    pid2=$!
    
    echo "First process PID: $pid1"
    echo "Second process PID: $pid2"
    
    echo "Waiting for the first task to complete..."
    wait $pid1
    echo "First task has completed!"
    
    echo "Waiting for the second task to complete..."
    wait $pid2
    echo "Second task has completed!"
  3. Ctrl+O を押してファイルを保存し、Enter を押し、最後に Ctrl+X でエディタを終了します。

  4. スクリプトを実行可能にします。

    chmod +x wait_pid_demo.sh
  5. スクリプトを実行します。

    ./wait_pid_demo.sh

    出力から、スクリプトが各プロセスの完了を個別に待機することがわかります。

$! 変数には、最近実行されたバックグラウンドプロセスの PID が格納されます。これにより、PID を取得し、後で wait コマンドで使用することができます。

wait の戻りステータスの処理

このステップでは、wait コマンドの戻りステータスを取得して処理する方法を学びます。この戻りステータスは、バックグラウンドプロセスの終了ステータスを反映します。

終了ステータスと戻りステータスの理解

Linux では、すべてのコマンドが完了すると終了ステータスを返します。終了ステータスが 0 の場合は通常成功を示し、0 以外の値はエラーまたは何らかの失敗を示します。

wait コマンドは、待機していたコマンドの終了ステータスを返します。複数のプロセスを待機している場合、最後に終了したプロセスの終了ステータスを返します。

これを示すスクリプトを作成しましょう。

  1. プロジェクトディレクトリに移動します。

    cd ~/project
  2. 成功するスクリプトを作成します。

    nano success_task.sh
  3. 以下の内容を追加します。

    #!/bin/bash
    echo "Starting success task"
    sleep 2
    echo "Success task completed successfully"
    exit 0 ## Exit with success status
  4. Ctrl+O を押して保存し、Enter を押し、最後に Ctrl+X で終了します。その後、実行可能にします。

    chmod +x success_task.sh
  5. 失敗するスクリプトを作成します。

    nano fail_task.sh
  6. 以下の内容を追加します。

    #!/bin/bash
    echo "Starting fail task"
    sleep 3
    echo "Fail task encountered an error"
    exit 1 ## Exit with error status
  7. Ctrl+O を押して保存し、Enter を押し、最後に Ctrl+X で終了します。その後、実行可能にします。

    chmod +x fail_task.sh
  8. 次に、wait コマンドのステータスを取得するスクリプトを作成します。

    nano wait_status_demo.sh
  9. 以下の内容を追加します。

    #!/bin/bash
    
    echo "Running a successful background task..."
    ./success_task.sh &
    wait
    
    wait_status=$?
    echo "Wait returned with status: $wait_status"
    
    if [ $wait_status -eq 0 ]; then
      echo "The background task succeeded!"
    else
      echo "The background task failed with status: $wait_status"
    fi
    
    echo ""
    echo "Running a failing background task..."
    ./fail_task.sh &
    wait
    
    wait_status=$?
    echo "Wait returned with status: $wait_status"
    
    if [ $wait_status -eq 0 ]; then
      echo "The background task succeeded!"
    else
      echo "The background task failed with status: $wait_status"
    fi
  10. Ctrl+O を押して保存し、Enter を押し、最後に Ctrl+X で終了します。その後、実行可能にします。

    chmod +x wait_status_demo.sh
  11. スクリプトを実行します。

    ./wait_status_demo.sh

    次のような出力が表示されます。

    Running a successful background task...
    Starting success task
    Success task completed successfully
    Wait returned with status: 0
    The background task succeeded!
    
    Running a failing background task...
    Starting fail task
    Fail task encountered an error
    Wait returned with status: 1
    The background task failed with status: 1

これは、wait コマンドの戻りステータスを使用して、バックグラウンドプロセスが正常に完了したかどうかを判断できることを示しています。これは、シェルスクリプトでのエラー処理に不可欠です。

実用アプリケーションの完成

この最後のステップでは、これまで学んだことを応用して、システムの準備プロセスをシミュレートするより複雑なスクリプトを作成します。このスクリプトは、複数のバックグラウンドタスクを調整し、すべてのタスクが正常に完了してから次の処理に進みます。

準備スクリプトの作成

まず、異なる準備タスクをシミュレートする 2 つのスクリプトを作成します。

  1. プロジェクトディレクトリに移動します。

    cd ~/project
  2. 最初の準備スクリプトを作成します。

    nano decorate_hall.sh
  3. 以下の内容を追加します。

    #!/bin/bash
    echo "Decorating the hall..."
    sleep 3
    echo "Hanging decorations..."
    sleep 2
    echo "Decoration complete."
    exit 0
  4. Ctrl+O を押して保存し、Enter を押し、最後に Ctrl+X で終了します。その後、実行可能にします。

    chmod +x decorate_hall.sh
  5. 2 番目の準備スクリプトを作成します。

    nano cook_feast.sh
  6. 以下の内容を追加します。

    #!/bin/bash
    echo "Preparing ingredients..."
    sleep 2
    echo "Cooking main dishes..."
    sleep 3
    echo "Preparing desserts..."
    sleep 1
    echo "Cooking complete."
    exit 0
  7. Ctrl+O を押して保存し、Enter を押し、最後に Ctrl+X で終了します。その後、実行可能にします。

    chmod +x cook_feast.sh

メインの調整スクリプトの作成

次に、これらの準備タスクを調整するメインスクリプトを作成します。

  1. メインスクリプトを作成します。

    nano prepare_feast.sh
  2. 以下の内容を追加します。

    #!/bin/bash
    
    echo "=== Preparation Ceremony Started ==="
    echo "Starting all preparation tasks..."
    
    ## Start the preparations in the background
    ./decorate_hall.sh &
    decoration_pid=$!
    
    ./cook_feast.sh &
    cooking_pid=$!
    
    echo "All tasks started. Waiting for completion..."
    
    ## Wait for decoration to finish
    wait $decoration_pid
    decoration_status=$?
    
    if [ $decoration_status -eq 0 ]; then
      echo "Decoration completed successfully."
    else
      echo "Error: Decoration failed with status $decoration_status"
      exit 1
    fi
    
    ## Wait for cooking to finish
    wait $cooking_pid
    cooking_status=$?
    
    if [ $cooking_status -eq 0 ]; then
      echo "Cooking completed successfully."
    else
      echo "Error: Cooking failed with status $cooking_status"
      exit 1
    fi
    
    ## All preparations completed successfully
    echo "=== All preparations completed successfully! ==="
    echo "The ceremony can now begin."
    
    ## Create a verification file to indicate successful completion
    echo "decoration_status=$decoration_status" > preparation_results.txt
    echo "cooking_status=$cooking_status" >> preparation_results.txt
    echo "overall_status=0" >> preparation_results.txt
    
    exit 0
  3. Ctrl+O を押して保存し、Enter を押し、最後に Ctrl+X で終了します。その後、実行可能にします。

    chmod +x prepare_feast.sh
  4. メインスクリプトを実行します。

    ./prepare_feast.sh

    すべての準備タスクが同時に実行される出力が表示され、メインスクリプトは各タスクが完了するのを待ってから全体の成功を宣言します。

スクリプトの理解

メインスクリプトの重要な部分を見てみましょう。

  • & を使用して各準備タスクをバックグラウンドで開始します。
  • $! を使用して各タスクの PID を取得します。
  • wait $pid を使用して各タスクの完了を待ちます。
  • 各タスクの終了ステータスを確認します。
  • 結果を含む検証ファイルを作成します。

このアプローチにより、以下のことが可能になります。

  1. 複数のタスクを同時に実行する。
  2. 各タスクの成功/失敗を監視する。
  3. 個々のタスクが失敗した場合、全体のプロセスを中止する。
  4. 結果の記録を作成する。

これは、複数のプロセスを調整して監視する必要があるシステム管理や自動化スクリプトで一般的なパターンです。

まとめ

この実験では、wait コマンドを使用して Linux でプロセスを効果的に管理および同期する方法を学びました。この重要なスキルを使えば、複数の同時操作を調整できる高度なシェルスクリプトを作成することができます。

習得した主要な概念は以下の通りです。

  • & 演算子を使用してプロセスをバックグラウンドで実行する
  • wait コマンドを使用して、バックグラウンドプロセスが完了するまで実行を一時停止する
  • PID で特定のプロセスを待機する
  • wait コマンドの戻りステータスを取得して処理する
  • バックグラウンドプロセスのエラー処理を実装する
  • 実際のシナリオで複数の同時タスクを調整する

これらのスキルは、Linux 環境でのシステム管理、自動化、およびシェルスクリプト作成において基本的なものです。プロセスの同期を適切に管理することで、並行性を活用しながらも依存操作の適切な順序を維持する、より効率的なスクリプトを作成することができます。

ビルドシステム、デプロイメントスクリプト、またはシステム管理ツールを開発する場合でも、複数のプロセスを調整する能力は、より強力で効率的なソリューションを作成するために不可欠なスキルです。