sedを使用して最初の一致の後に行を挿入する


245

どういうわけか、これに対する簡単な答えを見つけることができないようで、私は現在、少し時間の危機に瀕しています。sedコマンドを使用して特定の文字列に一致する最初の行の後にテキストの選択行を挿入する方法を教えてください。私が持っています ...

CLIENTSCRIPT="foo"
CLIENTFILE="bar"

そして、CLIENTSCRIPT=結果の行の後に行を挿入したい...

CLIENTSCRIPT="foo"
CLIENTSCRIPT2="hello"
CLIENTFILE="bar"

回答:


379

GNU sedを使用してこれを試してください:

sed '/CLIENTSCRIPT="foo"/a CLIENTSCRIPT2="hello"' file

インプレースで置き換えたい場合は、

sed -i '/CLIENTSCRIPT="foo"/a CLIENTSCRIPT2="hello"' file

出力

CLIENTSCRIPT="foo"
CLIENTSCRIPT2="hello"
CLIENTFILE="bar"

ドク

  • sed docを参照して検索\a(追加)

ありがとう!そして、ファイルの内容を印刷せずにファイルに書き戻すには?
user2150250 2013年

11
どちらもGNUを想定していることに注意してくださいsed。これは標準のsed構文ではなく、他のsed実装では機能しません。
ステファンChazelas

別の区切り文字を使用していたため、これがうまく機能しませんでした。RTFMを実行した後、正規表現を\で始め、次に区切り文字で始める必要があることに気付きました。
Christy

10
最初の試合のみにどのように適用されますか?マッチの後にテキストを追加するのは明らかですが、最初のマッチだけをどうやって知るのですか?
Mohammed Noureldin 2017

7
これにより、すべての一致の後にテキストが追加されます。
schoppenhauer 2017

49

標準のsed構文に注意してください(POSIXと同様に、sed(GNU、OS / X、BSD、Solarisなどの)準拠するすべての実装でサポートされています)。

sed '/CLIENTSCRIPT=/a\
CLIENTSCRIPT2="hello"' file

または1行で:

sed -e '/CLIENTSCRIPT=/a\' -e 'CLIENTSCRIPT2="hello"' file

-expressions(およびilesのコンテンツ-f)は改行で結合され、sedスクリプトのsed解釈を構成します)。

-iインプレース編集のオプションもGNU拡張であり、(FreeBSDのような)他のいくつかの実装-i ''はそれをサポートしています。

または、移植性のために、perl代わりに次を使用することもできます。

perl -pi -e '$_ .= qq(CLIENTSCRIPT2="hello"\n) if /CLIENTSCRIPT=/' file

それとも、使用することができますedex

printf '%s\n' /CLIENTSCRIPT=/a 'CLIENTSCRIPT2="hello"' . w q | ex -s file

2
私は間違っているかもしれませんが、電流sed -e '/CLIENTSCRIPT=/a\' -e 'CLIENTSCRIPT2="hello"' fileは最初のパラメーターの終わりにある引用符をエスケープし、コマンドを壊します。
放棄されたカート

1
@AbandonedCartは、Bourneのシェル、cshまたはrcファミリーで、'...'バックスラッシュが特別ではない強力な引用です。私が知っている唯一の例外はfishシェルです。
ステファンChazelas

1
MacOSのターミナル(およびその後、ターミナルで実行されるスクリプト)も例外のようです。別の構文を見つけましたが、とにかくありがとうございます。
放棄されたカート

1
@AbandonedCart、それは別のものです。sedここでは、macOS がPOSIXに準拠していません。そのため、移植性が悪いという私の声明は正しくありません(1行のバリアントの場合)。それが実際に私の規格の不適合または誤解であるかどうか、私はオープングループに確認を求めます。
ステファンChazelas

19

s次のコマンドを使用したPOSIX準拠のもの:

sed '/CLIENTSCRIPT="foo"/s/.*/&\
CLIENTSCRIPT2="hello"/' file

1
...新しい行の挿入もサポートします。大好きです!
Stephan Henningsen 2017

1
sed -e '/.../s/$/\' -e 'CLI.../'有効な文字を形成しないバイトシーケンスを含む行の問題を回避する方法も参照してください。
Stephane Chazelas

14

MacOS(少なくともOS 10)とUnixで同様に機能するSedコマンド(つまり、Gillesのような(現在受け入れられている)gnu sedを必要としません):

sed -e '/CLIENTSCRIPT="foo"/a\'$'\n''CLIENTSCRIPT2="hello"' file

これは、bashや、おそらく$ '\ n'評価引用スタイルを知っている他のシェルでも機能します。すべてを1行で記述して、古い/ POSIX sedコマンドで機能させることができます。CLIENTSCRIPT = "foo"(または同等のもの)に一致する行が複数ある可能性があり、追加の行を初めて追加するだけの場合は、次のように修正できます。

sed -e '/^ *CLIENTSCRIPT="foo"/b ins' -e b -e ':ins' -e 'a\'$'\n''CLIENTSCRIPT2="hello"' -e ': done' -e 'n;b done' file

(これにより、ファイルの残りの部分を循環する行挿入コードの後に​​ループが作成され、最初のsedコマンドに戻ることはありません)。

コメントに行が表示されたり、インデントされたりする場合に備えて、一致パターンに「^ *」を追加したことに気付くでしょう。100%完璧ではありませんが、一般的であると思われる他のいくつかの状況をカバーします。必要に応じて調整...

これらの2つのソリューションは、(行を追加する一般的なソリューションの)問題を回避します。新しい挿入された行にエスケープされていないバックスラッシュまたはアンパサンドが含まれている場合、sedによって解釈され、同じように出力されない可能性があります\n\0一致した最初の行になります。特に前に$ {var //}または別のsedステートメントなどを使用してすべてをエスケープする必要がある変数からの行を追加する場合に特に便利です。

このソリューションは、スクリプトで少し面倒ではありません(引用符と\ nは読みにくいです)。たとえば、関数内で、コマンドの置換テキストを行の先頭に配置したくない場合インデントされた行。$ '\ n'が通常の '\ n'一重引用符の値ではなく、シェルによって改行として評価されることを利用しました。

読みやすさのためにperl / awkでも勝てるかもしれないと思いますが、十分長くなります。


1
答えてくれてありがとう!最初のものは、AIX OSでも同様に機能します。
アビシェク2018

どのようにこれを行いますが、複数行挿入の場合ですか?
タツ

1
POSIX sedは、バックスラッシュ(source)でエスケープする場合、置換文字列のリテラル改行をサポートします。だから:s/CLIENTSCRIPT="foo"/&\ [Enter] CLIENTSCRIPT2="hello"/。バックスラッシュは、このコメントでの表示とは逆に、行の最後の文字でなければなりません(その後に空白はありません)。
TheDudeAbides

1
@tatsuの置換文字列の改行s///aおよびiコマンドの改行は、上記のコメントで説明したのと同じ方法を使用して「エスケープ」できます。
TheDudeAbides

4

これに対する回答を投稿するのは少し遅れるかもしれませんが、上記の解決策のいくつかは少し面倒です。

私はsedで簡単な文字列置換を試みましたが、うまくいきました:

sed 's/CLIENTSCRIPT="foo"/&\nCLIENTSCRIPT2="hello"/' file

記号は一致した文字列を反映し、\ nと新しい行を追加します。

前述のように、インプレースで実行する場合は、次のようにします。

sed -i 's/CLIENTSCRIPT="foo"/&\nCLIENTSCRIPT2="hello"/' file

別物。式を使用して照合できます。

sed -i 's/CLIENTSCRIPT=.*/&\nCLIENTSCRIPT2="hello"/' file

これが誰かを助けることを願っています


これは、GNU sedがデフォルトであるLinuxで正常に機能します。GNUsedは\n置換文字列を理解するためです。しかし、プレーンバニラ(POSIX)sedは置換文字列を認識しないため\n、これはBSDまたはmacOSでは機能しません—何らかの方法でGNU sedをインストールしていない限り。バニラsedを使用すると、改行を「エスケープ」して埋め込むことができます。つまり、行をバックスラッシュで終了し、[Enter]キーを押します(参照、の見出しの下[2addr]s/BRE/replacement/flags)。これは、sedコマンドが端末の複数行にまたがる必要があることを意味します。
TheDudeAbides

置換文字列でリテラルの改行を取得する別のオプションは、他の回答の1つで述べたように、BashのANSI-C引用機能を使用することです。
TheDudeAbides


1

私も同じような仕事をしていて、上記のperlソリューションを機能させることができませんでした。

これが私の解決策です:

perl -i -pe "BEGIN{undef $/;} s/^\[mysqld\]$/[mysqld]\n\ncollation-server = utf8_unicode_ci\n/sgm" /etc/mysql/my.cnf

説明:

のみ含まれている私の/etc/mysql/my.cnfファイル内の行を検索するために正規表現を使用[mysqld]し、それを置き換えます

[mysqld] collation-server = utf8_unicode_ci

collation-server = utf8_unicode_ciを含む行の後に効果的に行を追加し[mysqld]ます。


0

私は最近、MacとLinux OSの両方でもこれを行う必要があり、多くの投稿を閲覧して多くのことを試した後、私の考えでは、目的の場所にたどり着けませんでした。シンプルなパターンの標準コマンド、1つのライナー、ポータブル、拡張可能で、より多くの制約を追加できます。それから私はそれを別の視点で見てみました、それは私が「2ライナー」が私の基準の残りを満たしていれば「1ライナー」オプションなしで私ができることに気づいたときです。最後に、私がこのソリューションを思いついたのは、UbuntuとMacの両方で機能するので、みんなと共有したいものです。

insertLine=$(( $(grep -n "foo" sample.txt | cut -f1 -d: | head -1) + 1 ))
sed -i -e "$insertLine"' i\'$'\n''bar'$'\n' sample.txt

最初のコマンドでは、grepは「foo」を含む行番号を探し、cut / headは最初のオカレンスを選択します。オカレンスの後に挿入したいので、算術演算はその最初のオカレンスの行番号を1増やします。2番目のコマンドでは、インプレースファイル編集、挿入用の「i」です。ansi-cは新しい行「bar」を引用し、次に別の新しい行を引用します。その結果、「foo」行の後に「bar」を含む新しい行が追加されます。これら2つのコマンドはそれぞれ、より複雑な操作とマッチングに拡張できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.