n番目の行を削除する(一番下から)

n番目の行を削除する(一番下から)

ファイルの行数が不明です。 Unixプラットフォームで1行のコマンド(必要に応じて複数行を使用)でn行目(下から上へ計算)を削除する方法。

答え1

たとえば、下から4行目を削除するには、次のコマンドを使用しますsed

tac input | sed '4d' | tac

入力ファイルを上書きするには:

tmpfile=$(mktemp)
tac input | sed '4d' | tac > "$tmpfile" && mv "$tmpfile" input

答え2

純粋なsed:

  • もしNそれは1です:

    sed '$ d'
    

    簡単です。最後の行の場合、パターンスペースを削除すると印刷されません。

  • もしN1より大きい(で利用可能$n):

    sed "
       : start
       1,$((n-1)) { N; b start }
       $ { t end; s/^//; D }
       N
       P
       D
       : end
     "
    

    始める$((n-1))前にシェルによって拡張されることに注意してくださいsed

    この作品

    : start
    1,$((n-1)) { N; b start }
    

    お店N- パターンスペースに1行。このループで入力ストリームの終わりに達すると、sedパターンスペースは自動的に印刷されます(最後のn行も削除されません)。

    より多くの入力を仮定します。次に、最後の行に達する前に、次のフラグメントを繰り返します。

    N   # read the next line of input and append it to the pattern space
    P   # print the first line from the pattern space
    D   # delete the first line from the pattern space and start a new cycle
    

    このように、パターン空間は、入力に基づいて数行ずつ出力を「遅延」するバッファである。N入力の最後の行もこの部分から読み取ることができます。

    最後の行を読んだ後、以下が実行されます。

    $ { t end; s/^//; D }
    

    このコードが最初に実行されると、以前に成功した置換がなかったため、分岐しませtん。その後、このno-op置換が実行され、パターンスペースの最初の行は印刷されずに削除()されます。これがすぐに削除したい行です。新しいループが始まるので、同じコード行が最終的に再実行されます。今回はに分岐します。ends/^//DDtend

    sedスクリプトの終わりに達すると、パターンスペースは自動的に印刷されます。残りのすべての行が印刷されます。

    このコマンドは、n=2(有効)と(無効)に対してn=1同じ出力を生成します。状況に関係なく動作する単一のソリューションを探そうとしています。N。失敗したので特別なケースではN1です。

答え3

$n削除したい行数を保持する場合

以下を使用して1行を削除する

printf "\$-%d+1,\$-%d+1d\nwq\n" $n $n| ed -s file

最後のn行を削除

printf "\$-%d,\$d\nwq\n" $n | ed -s file

どこ

  • \$%d,\$dedに最後のn行を削除するように指示します(printfはnを挿入します)
  • wq作成を終えて終了します。
  • -s意志ed -s沈黙エド。

  • 削除する行が十分であることを確認するための条件はありません。

残念ながら、範囲は最後にsed...で指定できません。

答え4

headを組み合わせることでtailこれを達成できます。

もしn番目一番下の行を削除する必要があります。

  1. head標準入力から読み取って標準出力に報告します。銃-n上から始まる行
  2. tail下部の標準出力を読み、報告します。n-1標準入力の行。
  3. 全体として、行は順番に標準出力に報告され、最後から始まる* n番目の行はスキップされます。

この回避策は、head最後に報告された行以降に開かれたファイル記述のファイルオフセットを維持することに依存します。head標準入力がファイルからリダイレクトされると、GNUはこれを行うと思います。

n=200; tmpfile=$(mktemp) && { head -n -$n; tail -n -$((n-1)); }<file >"$tmpfile" \
    && mv -- "$tmpfile" file

関連情報