ファイルを繰り返すときに最後の行にあるかどうかはどうすればわかりますか?

ファイルを繰り返すときに最後の行にあるかどうかはどうすればわかりますか?

次のデータを含むファイルがありますlisting.txt

1
2
3
4
5

次に、次のコマンドを使用してファイルを繰り返し、各行で操作を実行します。

IFS=$'\n'
while IFS= read -r inc; do
    if [ $inc -eq 1 ]
    then
        echo "FIRST: $inc"
    else
        echo "MID: $inc"
    fi
done </home/user/listing.txt

しかし、最後の行であることを確認するオプションが見つかりません。私が最後の行にある場合、それを見つけるための最良の方法は何ですか?

私はループについて話している多くのページと、ファイルから最後の行を取得することについて話しているページを見ましたが、私のループがそれが最後の行にあることを知るのに役立つことはありません。

答え1

総行数とも呼ばれるファイルの最後の行番号を取得します。現在の行番号を追跡しながらファイルを繰り返します。現在の行番号が最後の行番号と同じ場合は、対処してください。

#!/bin/bash

file="some-file.txt"
last_line=$(wc -l < $file)
current_line=0

while read -r line; do
  current_line=$(($current_line + 1))

  if [[ $current_line -ne $last_line ]]; then 
    # is NOT last line
  else
    # IS last line
  fi 
done < $file 

答え2

最後の行にあるとはどういう意味ですか?これは、この行の後に行がないことを意味するので、1つの戦略は、ループ内の現在の行の後に他の行があることを確認することです。そうでなければ最後の行にあり、そうでなければ真ん中にあります。

もう1つの手法は、ループの外側の変数に行を保持し、ループの終わりに変数に最後の行を含めることです。これは中間計算が不正確になるという欠点があるが、解決策を見つけることもできる。

答え3

WAFが説明で述べた内容を繰り返すには、それを使用してwcループの前の行数を取得してテストして、最後の行をキャプチャできます。

IFS=$'\n'
last=$(</home/user/listing.txt wc -l)
while IFS= read -r inc; do
    if [ $inc -eq 1 ]
    then
        echo "FIRST: $inc"
    elif [ $inc -eq $last ]
        echo "LAST: $inc"
    else
        echo "MID: $inc"
    fi
done </home/user/listing.txt

答え4

1つのオプションは、ループの一部を「解放」して、次の行の状態を使用して現在の行の処理を決定できるようにすることです。

{
  IFS= read -r current
  while IFS= read -r next; do
    echo "MID: $current"
    current=$next
  done
  echo "LAST: $current"
} </home/user/listing.txt

このようなループは行数やファイルの内容について何も知る必要はありません。特に、これはデータストリーム、つまり他のプロセスからパイプで接続されたデータと連携します(以下の例を参照)。

最初の行とは異なる操作を行うには、ループを少し広げます。

printf '%s\n' a b c d e | {
  IFS= read -r first
  echo "FIRST: $first"
  IFS= read -r current
  while IFS= read -r next; do
    echo "MID: $current"
    current=$next
  done
  echo "LAST: $current"
}

出力:

FIRST: a
MID: b
MID: c
MID: d
LAST: e

関連情報