whileループとreadコマンド:改行の有無による行の表示制御について

スポンサーリンク
whileループとreadコマンド:改行の有無による行の表示制御について ノウハウ
whileループとreadコマンド:改行の有無による行の表示制御について
この記事は約4分で読めます。
よっしー
よっしー

こんにちは。よっしーです(^^)

今日は、Bashスクリプトでwhile文を使用したときに最終行だけ処理をされなかった問題についてご紹介します。

スポンサーリンク

背景

下記のデータファイル(sample.dat)があったとします。

1
2
3

このとき、下記のBashスクリプト(sample.sh)を起動します。

#!/bin/bash

while read line
do
  echo ${line}
done < sample.dat

すると、実行結果は下記のようになりました。

% /bin/sh sample.sh
1
2

最終行の3がなぜか出力されないという問題が発生しています。

解決策

案1

sample.datの3の後に空行をいれる。

1
2
3

sample.shを起動します。

% /bin/sh sample.sh
1
2
3

期待した結果になりました。ただ、これだと、毎回datファイルの最終行に空行が入っているかどうかを確認しないといけないので、最終行に空行がはいっていなくても期待した結果になるようにsample.shを修正したいと思います。

案2

sample.shを下記のように修正します。

#!/bin/bash

while read line || [ -n "${line}" ]
do
  echo ${line}
done < sample.dat

sample.shを起動します。

1% /bin/sh sample.sh
1
2
3

期待した結果になりました!

解説

#!/bin/bash

while read line || [ -n "${line}" ]
do
  echo ${line}
done < sample.dat

このスクリプトは、Bashシェルスクリプトで書かれています。以下にコードの解説をします。

#!/bin/bash

この行は、スクリプトをBashシェルで実行することを指定しています。

while read line || [ -n "${line}" ]

この行は、ループを開始します。readコマンドを使って変数lineに1行ずつ入力を読み込みます。||演算子は、前のコマンドが失敗した場合に次のコマンドを実行することを意味します。[ -n "${line}" ]は、変数lineが空でないかどうかをチェックする条件です。つまり、読み込んだ行が空でない限り、ループは続行されます。

do
  echo ${line}
done

この部分は、ループの本体です。echoコマンドを使用して、変数lineの値を出力します。${line}は変数lineの値を参照するための構文です。

< sample.dat

この部分は、ファイルsample.datからの入力をループに渡すためのリダイレクションです。<演算子は、ファイルからの入力を示します。

したがって、このスクリプトは、sample.datというファイルから1行ずつ読み込み、それぞれの行を表示するという動作を行います。ループは、ファイルの終端に到達するまで続きます。

最終行が出力されない理由

readコマンドは、デフォルトでは改行文字を区切り文字として扱います。つまり、改行文字がない行は入力として認識されず、読み飛ばされます。

while read lineの行でreadコマンドを呼び出すと、readコマンドは標準入力から1行ずつ読み込みます。その際、改行文字を区切り文字として使用します。もし改行文字がない行が現れると、readコマンドは終端に到達せずにブロックされ続け、次の行の読み込みを試みます。そのため、改行文字がない行は無視され、表示されません。

ただし、ループを終了させるためには、入力からの読み込みが終了する必要があります。そのためには、ファイルの終端に到達する必要があります。ファイルの終端に到達した場合でも、-n "${line}"の条件があるため、最後の行が空でない場合はループが続行されます。

したがって、改行文字がない行が表示されないのは、readコマンドのデフォルトの動作によるものです。

改行がない行の read line の結果がfalseのために、while文の処理が実行されないのが原因のようです。

ただ、$lineにはデータが入っているので、$lineのデータの有無を条件に付け加えて対応したのが、今回の解決案になります。

おわりに

今日は、Bashスクリプトでwhile文を使用したときに最終行だけ処理をされなかった問題についてご紹介しました。

よっしー
よっしー

何か質問や相談があれば、遠慮なくコメントしてください。また、エンジニア案件についても、いつでも相談にのっていますので、お気軽にお問い合わせください。

それでは、また明日お会いしましょう(^^)

コメント

タイトルとURLをコピーしました