正規表現に一致する最初のN行を削除し、最後の行を維持する必要があります。
28test
32test
something else
6test
something else
something else
4test
entirelysomethingelse
こんなことが欲しい
something else
something else
something else
4test
entirelysomethingelse
試してみると、sed
1行と複数の文字列でのみ機能するようです。
正規表現を使用しました。^(.*test)$
答え1
最後の一致ラインのみを維持する簡単な方法は、入力を逆方向に印刷し、最初の一致ラインのみを選択してからパイプから出力を逆方向に印刷することです。tac
からの仮定GNUコアユーティリティ利用可能:
tac input_file | awk '!/test$/ || !seen++' | tac >output_file
所定の位置で編集(で行ったように)コメント)は通常、引数として提供されたファイルを処理された出力で上書きするスクリプトまたは関数にコマンドをラップすることによって取得されます。
tmpdir=$(mktemp -d)
cp input_file "$tmpdir/file"
tac "$tmpdir/file" | awk '!/test$/ || !seen++' | tac >input_file
rm -r "$tmpdir"
シェルがそのpipefail
オプションをサポートしている場合(setopt PIPE_FAIL
busybox ash、yashを使用してbash、ksh93、mksh、zshを正常にテストできます)、および:エラー(パイプラインのどこでも発生するエラーを含む)をset -e
使用すると、これをより安全にする作成できます。set -o pipefail
停止する前に削除されます。
これをサポートするプラットフォームでは、問題が発生してもデータ損失を気にしないと仮定すると、次のことも使用できます。
{ rm file; tac | awk '!/test$/ || !seen++' | tac >file; } <file
これにより、inodeが変更されますfile
(多くの一般的なツールによって提供される内部編集オプションに似ています)。
逆に、最初のアイテムを削除するにはNここで仮定すると、一致する行N= 2:
awk '!/test$/ || ++seen > 2' input_file >output_file
awk
この場合、GNUは簡単に編集できる他のライブラリ(特に独自の「内部」ライブラリ)をインポートできますgawk
。
awk -i inplace '...' file
これについて詳しくは、次をご覧ください。この他の答えU&Lから。
答え2
上記の「パターンに一致する最初のN行削除」オプションの場合、sed
予約済みスペース(追加バッファ)にカウンタを設定できます。
sed -r '/test$/!b;x;s/$/-/;/-{4}/!{x;d};x' file
/test$/!b
- パターンが一致しない場合は無条件にジャンプします。
x
- 予約されたスペースのモードと内容を切り替えます。
s/$/-/
- 各一致のカウンターの末尾に文字を追加します。私の場合はハイフンです。
/-{4}/!{x;d}
- カウンターに含まれる文字が4文字未満の場合、パターンスペースから行を削除します。