入力ファイルラインのループで最後の反復を表示する方法はありますか?

入力ファイルラインのループで最後の反復を表示する方法はありますか?

direction次の行を含むファイルがあるとします。

east
north
south
west
south-west

ループを使用し、echoシェルスクリプトから次の出力を生成します。

Direction: east
Direction: north
Direction: south
Direction: west
Last direction: south-west

つまり、スクリプトの最後の行で別の操作を実行したいと思います。

答え1

bashファイルの終わりを検出する方法はありませんが(次の行を読み取ろうとせずに失敗します)、Perlはそのeof機能を使用できます。

$ perl -n -e 'print "Last " if eof; print "Direction: $_"' direction 
Direction: east
Direction: north
Direction: south
Direction: west
Last Direction: south-west

注:echoBashとは異なり、Perlのステートメントは1.印刷する文字列に含めて明示的に指定するか、2. Perlのコマンドラインオプションを使用するか、3.文字列に新しい行を含める場合を除きprint、改行を印刷しません。 - の場合なので改行文字を削除するのによく必要です。\n-l$_chomp()

Perlでは、BTWは$_現在の入力ラインです。あるいは、実際の変数名を指定しないループの基本イテレータ(しばしば「現在のエントリ」と呼ばれます)たくさん$_指定しない場合、Perl関数と演算子はデフォルト/暗黙のパラメータとして使用されます。表示man perlvarと検索$_

sedまた動作します。$アドレスはファイルの最後の行と一致します。

$ sed -e 's/^/Direction: /; $s/^/Last /' direction 
Direction: east
Direction: north
Direction: south
Direction: west
Last Direction: south-west

ルールの順序がsed重要です。私の最初の試みは間違った方向に進みました(そして「方向:最後の南西」が印刷されました)。この sed スクリプトは常に各行の先頭に "Direction:" を追加します。最後の行($)では、前のステートメントによって変更された行の先頭に「Last」を追加します。

答え2

ループは、実際に終わりに達しない限り、いつ終わりに到達したかを知りません。したがって、ファイルを2回処理します。 1回は行数を取得し、もう1回は出力を処理するか、各反復で前の値を印刷し、ループを終了したときに最後の値を印刷します。

prev=""
while read direction; do 
    if [ -n "$prev" ]; then 
        echo "Direction: $prev"
    fi
    prev="$direction"
done < direction
echo "Last Direction: $prev" 

答え3

の変種FelixJNの答え、行を配列として読み込みますが、bashループの代わりにbash組み込みを使用します。

mapfile -t DIR < direction
printf "Direction: %s\n" "${DIR[@]::${#DIR[@]}-1}"
printf "Last direction: %s\n" "${DIR[-1]}"

マップファイル標準入力を項目ごとに1行ずつ配列として読み取るBash 4に追加された組み込み関数。この-tオプションは改行文字を削除します。

printfそのフォーマット文字列は、すべての入力パラメータが使い果たされるまで繰り返し適用されます。

答え4

pastetailおよび次のものを混在させることができますhead

$ paste -s -d'\n' <(head -n -1 direction | sed 's/^/Direction: /') <(tail -n1 direction | sed 's/^/Last direction: /')
Direction: east
Direction: north
Direction: south
Direction: west
Last direction: south-west

  • paste -s -d'\n'-d'\n'オプションとオプションとともに、改行文字を区切り文字として使用します-s

    -s、--
    serial並列ではなく一度に1つのファイルを貼り付けます。

  • head -n -1最後の行とパイプを除くすべての行を検索し、その行sedにのみ必要なコマンドを実行します。

  • tail -n1 fileファイルの最後の行を検索してパイプし、その行sedに必要なコマンドのみを実行します。


またはより簡潔にcat代わりに使用してくださいpaste@MickMatteoによるコメント:

$ cat <(head -n -1 direction | sed 's/^/Direction: /') <(tail -n1 direction | sed 's/^/Last direction: /')

関連情報