
2つのコマンドを含むスクリプトをテストしていますsed
。最初のコマンドは入力から行を削除し、2番目のコマンドは入力の最後に行を追加します。
$ cat input.txt
Line 1
Line 2
Line 3
$ sed '/Line 1/d;$aAppended line' input.txt
Line 2
Line 3
Appended line
$ sed '/Line 2/d;$aAppended line' input.txt
Line 1
Line 3
Appended line
今まではそんなに良くなった。ただし、削除するために選択した行が最後に入力された行である場合、スクリプトの2番目のコマンドは実行されません。
$ sed '/Line 3/d;$aAppended line' input.txt
Line 1
Line 2
sed
入力行は一度に読み取られ、それ以上読み取る行がなくなるまで各行でスクリプトが「実行」されるので、私のスクリプトが決して「完了」(つまり追加されていないAppended line
)という事実が意味があることを学びました。 。
それでもこれは私にとって問題になります(まだ追加する必要がありますAppended line
)。この問題についてよく知っている人はいますか?もしそうなら、「標準的な解決策」はありますか?私の考えに代わるもの(最後の行を削除してから1つ追加)は次のとおりです。変える:
$ sed 's/Line 3/Appended line/' file.txt
Line 1
Line 2
Appended line
これが私の唯一の選択ですか?
答え1
d
マニュアルページのコマンドsed
:
パターンスペースを削除します。次のサイクルを開始してください。
複数のsed
コマンドが指定された順序で実行されるため、「次のサイクルの開始」は、実際に行が削除された後(現在のサイクルの)削除された行に適用される可能性がある後続のコマンドの実行を停止することを意味します。したがって、Line 3
最後の行で削除されると、新しいループが始まりますa
未定最後の行に適用すべきコマンドは実行されません。
この問題を解決するには、コマンドの順序を逆にするだけです。
sed -e '$aAppended line' -e '/Line 3/d'
またはGNU固有のコードと同等の標準コード:
sed '$a\
Appended line
/Line 3/d'
これにより、最後の行の後にテキストが追加されます。今後 Line 3
削除されます(そしてループは終了します)。
そのa
行は追加されません。空間をパターン化する;引用するPOSIX、それ後で出力するテキスト予約、テキスト[...]入力ラインを取得する前に、標準出力に書き込む必要があります。d
[...] したがって、そのオプションの影響を受けません-n
。
答え2
sed オプションを使用すると、-n
コンテンツの削除からコンテンツの印刷に問題を変更できます。
#!/usr/bin/sed -nf
/Line 3/!p
$aAppended line
これは/text/!
否定です。つまり、含まれていない行にのみ一致しますtext
。そして、p
残りのスクリプトの実行を停止しても副作用はなく、新しいループは発生しません。
答え3
perl
他の人はすでにこれが起こる理由を説明しているので、代わりにこの問題のないを使用する別のソリューションを提供しますsed
。
$ cat input.txt
Line 1
Line 2
Line 3
$ perl -lne 'print unless /Line 3/; END{print "Appended line"}' input.txt
Line 1
Line 2
Appended line
答え4
s、g、およびp(-nを含む)以外のsed構成を使用する場合は、明確さ、堅牢性、および移植性のためにawk(別の必須POSIXテキスト処理ツール)を使用するのが最善です。
すべてのUnixシステムのすべてのシェルでawkを使用してください。
$ awk 'NR!=1; END{print "Appended line"}' input.txt
Line 2
Line 3
Appended line
$ awk 'NR!=2; END{print "Appended line"}' input.txt
Line 1
Line 3
Appended line
$ awk 'NR!=3; END{print "Appended line"}' input.txt
Line 1
Line 2
Appended line