忍者ブログ

プログラミングの練習

プログラミングの問題やプログラミング関連知識、ソフトウェアのテストについてのブログです

【Bash応用】ファイル記述子(ファイルディスクリプタ)を活用したファイル読み込み|exec と read -u の仕組み

Bashスクリプトでファイルを読み込む際、done < sample.txt のようにループの末尾でリダイレクトする以外に、ファイル記述子(ファイルディスクリプタ)を直接開いて管理する方法があります。

今回は exec コマンドと read -u オプションを使った高度なファイル読み込みの仕組みとメリットについて解説します。





1. サンプルコードと実行結果

ファイル記述子番号「3」を割り当ててファイルをオープンし、ループ内で読み出すスクリプトです。


  • ① ソースコード(read_fd.sh)

    #!/bin/bash

    exec 3<sample.txt

    while read -u3 line

    do

      echo $line

    done

  • ② 実行結果

    $ ./read_fd.sh

    abc

    123

    456



2. exec と read -u の仕組み解説

通常の while read line ... done < file との違いや、各コマンドの挙動を整理します。


  • Point:exec によるファイル記述子の永続的割り当て

    ・exec 3<sample.txt:現在のシェルプロセス上で ファイル記述子番号「3」 を作成し、sample.txt を読み取り専用として開きます。スクリプトが終了するか、明示的に閉じるまでファイルが開きっぱなしの状態で維持されます。

    ・read -u3 line:標準入力(通常はキーボード・番号0)ではなく、ファイル記述子番号 3 から1行読み込むことを直接指定するオプションです。

    ・通常のリダイレクト(done < file)のように「ループの範囲」に縛られず、スクリプト内の任意の場所で順番にファイルから読み込むことができます。

【解説と補足ポイント:この書き方が活躍する実践的ユースケース】



■ 1. 複数のファイルを同時に1行ずつ読み込むとき

通常のリダイレクトでは1つの入力しか扱いにくいですが、ファイル記述子を分けることで(例:3<file1.txt、4<file2.txt)、2つのファイルを並行して1行ずつ比較・処理できます。



■ 2. ループ内で対話型コマンドや SSH 接続を行うとき

while read line; do ssh host ...; done < list.txt のようにループ内で ssh コマンドなどを実行すると、ssh側が残りのテキスト行(標準入力)を全て横取りしてしまい、ループが1回で終わるトラブルが発生します。

read -u3 でファイル記述子を標準入力(0)から切り離しておくことで、この干渉(標準入力のバッティング)を完全に防止できます。



■ 明示的にクローズする作法

使い終わったファイル記述子は、以下の記述で閉じる(クローズする)のがベストプラクティスです。

exec 3<&- # ファイル記述子 3 を閉じる



3. まとめ

exec 3<ファイル名 と read -u3 は、Bashにおいてファイル記述子を明示的に操作するための手法です。


複数ファイルの並行処理や、ループ内での外部コマンド(SSHやscp等)実行時の標準入力バッティング回避など、高度なスクリプト作成に欠かせない重要なテクニックです。


PR