
指定された文字列を含むファイルの最後の行を検索し、その一致の後に行を追加します。例:
入力:
Apple
Banana
Apple
Orange
Apple
Grapefruit
出力:
Apple
Banana
Apple
Orange
Apple
I am new string replaced at last apple
Grapefruit
答え1
GNU を使用するとsed
次のことが可能になります:
sed ':a;N;$! ba;s/.*\nApple/&\nYour appended line/'
パターンは、ファイルの末尾 (アドレス ) に到達していない間 ( )、:a;N;$! ba
ファイルからバッファに行を追加します(でにジャンプします)。したがって、ループを終了すると、すべての行がバッファにあり、検索パターンはで始まる最後の行までファイル全体に一致します。置換文字列の は、一致全体を挿入し、テキストを追加します。N
$
!
:a
ba
.*\nApple
Apple
&
sed
他のバージョンでも動作するポータブルソリューションは
sed -e ':a' -e 'N;$! ba' -e 's/.*\(\n\)Apple/&\1Your appended line/'
ここでは、スクリプトはラベルで分割され、\n
置換文字列 (GNU 以外では動作が保証されません) を使用する代わりに、参照でsed
囲まれたパターンからのものを参照します。\(\)
\1
答え2
この例を見たここ
sed -i -e "\$aTEXTTOEND" <filename>
情報:
i: edit files in place
e: add the script to the commands to be executed
$: sed address location
a: append command
TEXTTOEND: text to append to end of file
答え3
入力例は という名前のファイルであると想定していますfruits.txt
。
「Apple」の最後の出現の後に行を挿入したい場合は、sed
次のようにします。
sed -rz 's/(^(.*\n)?Apple)(\n|$)/\1\ninserted line\n/'
この-r
オプションは、拡張正規表現を有効にします。
この-z
オプションはsed
、通常の改行文字の代わりに NUL 文字 (ASCII コード 0) を行区切り文字として使用するように指示します。この方法では、テキスト ファイル全体が行ごとではなく一度に処理されます。
このsed
コマンドは、 内のs/PATTERN/REPLACEMENT/
(拡張、 のため-r
) 正規表現を検索しPATTERN
、評価された文字列に置き換えますREPLACEMENT
。
正規表現は、(^(.*\n)?Apple)(\n|$)
先頭 ( ^
) から最後の とApple
それに続く改行 ( \n
) またはファイルの末尾 ( $
) までの任意の数の行に一致します。
これで、この一致全体が に置き換えられます\1\ninserted line\n
。ここで、 は\1
最初の一致グループの元のコンテンツ、つまり までのすべてを表します。したがって、実際には、最後の「Apple」の直後に、前後に改行 ( )Apple
が挿入されます。inserted line
\n
これは、「Apple」行がファイル内の最初の行、最後の行、または唯一の行である場合にも機能します。
入力ファイルの例 (動作を明確にするために、例に 1 行追加しました):
Apple
Banana
Apple
Orange
Apple
Cherry
出力例:
Apple
Banana
Apple
Orange
Apple
inserted line
Cherry
結果に満足し、fruits.txt
変更を出力するだけでなくその場で編集したい場合は、次の-i
オプションを追加できます。
sed -irz 's/(^(.*\n)?Apple)(\n|$)/\1\ninserted line\n/'
ただし、ファイルの末尾にテキスト行を追加するだけの場合は、sed
最適なツールではありません。
>>
その場合は、Bash の追加出力リダイレクトを使用するだけです。
echo "I am new string replaced at last apple" >> fruits.txt
は>>
、左側のコマンドの標準出力 (echo
ここでのコマンドは単に引数を標準出力に出力します) を取得し、右側で指定されたファイルに追加します。ファイルがまだ存在しない場合は、作成されます。
答え4
この回答では:
- sed+tac (二重入力反転)
- 二重入力のAWK
- 二重入力の Perl
- 二重入力反転機能を備えた代替 Perl
sed + タック
このアプローチでは、最初にファイルを逆順にし、sed を使用して最初の一致を検索し、最初の一致の後に必要なテキストを挿入し、テキストを再度逆順にするという 3 つのプロセスを使用します。
$ tac input.txt | sed '0,/Apple/{s/Apple/NEW THING\n&/}' | tac
Apple
Banana
Apple
Orange
Apple
NEW THING
something else
something other entirely
blah
基本的な考え方は、以下に記述する代替 Perl バージョンと同じです。つまり、行の逆リストの最初の一致が、元のリストの最後の一致になります。このアプローチの利点は、ユーザーにとってシンプルさと読みやすさです。
このアプローチは小さなファイルには適していますが、大きなファイルには扱いにくく、大量の行を処理するのにかなりの時間がかかる可能性があります。
AWK
Awk は、あなたがやろうとしていることに対して、ちょっとしたフレンドリライナーになることができます:
$ awk -v n="AFTER LAST APPLE" 'NR==FNR&&/Apple/{l=NR};NR!=FNR{if(FNR==l){print $0;print n}else print}' input.txt input.t>
Apple
Banana
Apple
Orange
Apple
AFTER LAST APPLE
something else
something other entirely
blah
ここでの基本的な考え方は、入力ファイルを awk に 2 回渡すことです。1 回目は最後の Apple がどこにあるかを見つけ、2 回目は最初の反復で見つかった最後の「apple」の位置を渡したときにテキストを挿入します。
これを機能させるための鍵は、NR
(処理されたすべての行、合計をカウントし続ける) およびFNR
(現在のファイル内の行番号) 変数を評価することです。これら 2 つのファイルが等しくない場合は、2 番目のファイルを処理していることがわかり、Apple の最後の出現場所を見つける最初のパスが完了したことがわかります。
ファイルを 2 回読み取るため、パフォーマンスはファイルのサイズに依存しますが、ファイルを 2 回反転する必要がないため、sed + tac の組み合わせよりも優れています。
パール
perl -sne '$t+=1;$l=$. if /Apple/ and $.==$t;
if($t!=$.){if($.==$l){print $_ . $n . "\n";}else{print $_}};
close ARGV if eof;' -- -n="AFTER LAST APPLE" input.txt input.txt
Perl のソリューションは、AWK のソリューションと同じ考え方に従います。入力を 2 回渡し、最初に渡されたファイルを使用して Apple が最後に出現する場所を見つけ、その行番号を$l
変数に格納します。ここで awk と異なるのは、perl には変数がないため、その目的でと をFNR
使用する必要があることです。$t+=1
close ARGV if eof
ここでも異なるのは、-s
スイッチを使用すると Perl で引数を渡すことができることです。この場合、挿入する文字列は-n
スイッチ経由で渡されます。
代替Perl
Perl でこれを行う別の方法を紹介します。アイデアは、ファイルを行の配列に読み込み、その配列を逆にすることです。逆にした配列で最初に一致するのは、元の行リストの最後の行です。したがって、その行の前に必要なテキストを挿入し、リストを再度逆にすることができます。
$ perl -le '@a1=<>;END{do{push @a2,"NEW LINE\n" and $f=1 if $_ =~ /Apple/ and !$f; push @a2,$_} for reverse(@a1); print reverse(@a2)}' input.txt
Apple
Banana
Apple
Orange
Apple
NEW LINE
something else
something other entirely
blah