A行で始まる Fred Flintstoneには、何らかの文字列が追加されます。指定されたFred Flintstoneの出現を探して追加します。
このようなパターンのオカレンスのいずれかにこのコマンドを使用するにはどうすればよいですか?私は試した
sed '/Fred Flintstone/ s/$/ someString/2' filename
どうやら上記のものは機能していません。すべてのオカレンスでうまく機能しますが、特定のオカレンスでは機能しません。 (最初または2番目または3番目[いずれか1つ]を交換したい場合)
サンプルFile1:
Fred Flintstone
Johnson Stone
Fred Flintstone
Fred Flintstone
Michael Clark
必要な出力ファイル1:
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark
sed
に言及しましたが、これらはawk
- yタスクの一種です:
awk -v pat="Fred Flintstone" '$0 ~ pat {count++;\
if (count == 2) { $0 = $0" someString" ;} ;}; 1' file.txt
-v pat="Fred Flintstone"
は、pat
式内で使用される変数awk
として一致する正規表現パターンを保存します
$0 ~ pat
は、一致するレコードをpat
に対してチェックします。一致した場合、count
変数は1増加し、count
が2の場合、レコードは現在のコンテンツにsomeString
({count++; if (count == 2) { $0 = $0" someString" ;} ;}
)を加えたものとしてリセットされます。
1はイディオムです。そのままtruthy、すべてのレコードが印刷されます
例:
% cat file.txt
Fred Flintstone
Johnson Stone
Fred Flintstone
Fred Flintstone
Michael Clark
% awk -v pat="Fred Flintstone" '$0 ~ pat {count++; if (count == 2) { $0 = $0" someString" ;} ;}; 1' file.txt
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark
この単純なsed
コマンドを使用すると、ループを使用せずに(ブランチツーエンドを使用)、GNU拡張子を必要とせずに、またはファイル全体を一度に読み取らずに、選択的に変更を行うことができます。
sed -r '/Fred Flintstone/ {x; s/$/#/; /^#{2}$/ {x; s/.*/& someString/; b}; x}'
説明:
-r
-拡張正規表現を使用/Fred Flintstone/
-このパターンに一致する行の場合:x
-パターンスペースを交換し、スペースを保持します(カウンターをアクティブにします)s/$/#/
-カウンターに文字を追加します/^#{2}$/
-カウンターの長さが2の場合(任意の値に置換)x
パターンスペースを交換し、スペースを保持します(カウントされた入力行をアクティブにします)s/.*/& someString/
-目的の行に文字列を追加しますb
-印刷できるように、この行の処理の最後までスキップしますx
-パターンスペースを交換し、スペースを保持します(文字列に一致するがカウントには一致しない行をアクティブにします)説明のインデントレベルは、中括弧のネストのレベルを示しています。
他のすべての行は処理せずに通過し、印刷されます。
ファイル全体をメモリに丸memoryみせずにsed
で実行する方法を次に示します。
N
をパターンスペースに追加しますTa
$q
は、一致せずにファイルの終わりに達した場合にループを終了します。
そう
sed '/Fred Flintstone/ {:a; $q; N; s//& someString/2; Ta;}' File1
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark
T
はGNU拡張機能ですが、POSIX sed
でもt; ba
を使用して同じことができます
うーん...これについてもう少し考えた後、実際に新しいテキストを他のすべての出現に追加します-2番目だけでなく。本当に使用する必要があるのが2番目のオカレンスのみの場合、私がそれを行うことができる唯一の方法は次のとおりです。
GNU sed
は、パターンのfirstインスタンスに対処するためのトリックを提供します
0,/pattern/
そう
sed -e '0,/Fred Flintstone/ s//Barney Rubble/' \
-e '0,/Fred Flintstone/ s//& someString/' \
-e '0,/Barney Rubble/ s//Fred Flintstone/
' File1
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark
Edの使用を気にしない場合は、最初の行に移動して、あるインスタンスから次のインスタンスに前方一致することにより、2番目のインスタンスをより直接アドレス指定できます。
ed -s File1 << \EOF
1;#
/Fred Flintstone/,/Fred Flintstone/ s//& someString/
,p
q
EOF
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark
またはワンライナーとして
printf '1;#\n/Fred Flintstone/,/Fred Flintstone/ s//& someString/\n,p\n' | ed -s File1
,p
をw
に置き換えることにより、edバージョンをインプレースにできます。
ex
、POSIX指定ファイルエディター の別の使用例(これはvi
の前身であり、依然としてvi
の一部です。)
printf '%s\n' '0/Fred Flintstone///s/$/ someString/' x | ex filename
ここでの魔法は、Sed、Awkおよび同様のツールとは異なり、ex
はすべての行でコードを実行しないことです。カーソルを動かしたり、コマンドを与えたりできます。
この場合、行番号0
(最初の行のFred Flintstoneが考慮されるようにします)を指定し、その後にファイル一致の最初の行を参照する正規表現/Fred Flintstone/
を続けますその正規表現の後に別の正規表現//
が続きます。空の場合、最後の正規表現を再利用するため、ファイル内のsecond行を参照します一致する;そして、すでに知っているs
コマンドを使用します。
x
コマンドは、変更を保存して終了することを意味します。
printf
を使用して、コマンドをex
に送ります。