web-dev-qa-db-ja.com

sedに改行を挿入する(Mac OS X)

Sedの置換部分に改行を挿入するにはどうすればよいですか?

このコードは機能していません:

sed "s/\(1234\)/\n\1/g" input.txt > output.txt

input.txtは次のとおりです。

test1234foo123bar1234

output.txtは次のようになります。

test
1234foo123bar
1234

しかし、私はこれを手に入れました:

testn1234foo123barn1234

注:

この質問は、特にMac OS Xバージョンの「sed」に関するものであり、コミュニティは、たとえばLinuxバージョンとは異なる動作をすることに注目しています。

39
Tyilo

Sedバージョンは、RHSで_\n_をサポートしていないようです(置換の右側)。 SED FAQ Eric Pementが管理しているものを読んで、可能な解決策を選択してください。最初にリテラルの改行文字を挿入することをお勧めします。

以下はその引用です。


4.1。置換のRHSに改行を挿入するにはどうすればよいですか?

Sedのいくつかのバージョンでは、_\n_をRHSに直接入力できます。その後、出力で改行に変換されます:ssed、gsed302a +、gsed103(_-x_スイッチ付き)、sed15 +、sedmod、UnixDOS sed。最も簡単な解決策は、これらのバージョンのいずれかを使用することです。

Sedの他のバージョンについては、次のいずれかを試してください。

(a)Bourne Shellからsedスクリプトを入力する場合、スクリプトが「単一引用符」または2つのバックスラッシュを使用する場合は、1つのバックスラッシュ_\_を使用します_\\_スクリプトに「二重引用符」が必要な場合。次の例では、2行目の先頭の_>_がシェルによって生成され、ユーザーに入力を促すようになっています。ユーザーは、コマンドを終了するために、スラッシュ、一重引用符、Enterの順に入力します。

_ [sh-Prompt]$ echo twolines | sed 's/two/& new\
 >/'
 two new
 lines
 [bash-Prompt]$
_

(b)スクリプト内で1つのバックスラッシュ_\_を持ち、すぐに改行が続くスクリプトファイルを使用します。これにより、「置換」部分に改行が埋め込まれます。例:

_ sed -f newline.sed files

 # newline.sed
 s/twolines/two new\
 lines/g
_

Sedの一部のバージョンでは、末尾のバックスラッシュが不要な場合があります。その場合は、削除します。

(c)未使用の文字を挿入し、出力をtrにパイプします。

_ echo twolines | sed 's/two/& new=/' | tr "=" "\n"   # produces
 two new
 lines
_

(d)Gコマンドを使用します。

Gは、改行とホールドスペースの内容をパターンスペースの最後に追加します。保留スペースが空の場合、とにかく改行が追加されます。改行は_\n_としてパターンスペースに格納され、\(...\)をグループ化してアドレス指定し、RHSで移動できます。したがって、前に使用した「twolines」の例を変更するには、次のスクリプトが機能します。

_ sed '/twolines/{G;s/\(two\)\(lines\)\(\n\)/\1\3\2/;}'
_

(e)行を分割せずに、行全体を挿入します。

行を変更せず、パターンの前後に完全な行のみを挿入する場合、手順ははるかに簡単です。 i(挿入)またはa(追加)コマンドを使用して、外部スクリプトによる変更を行います。正規表現に一致する各行の前に_This line is new_を挿入するには:

_ /RE/i This line is new               # HHsed, sedmod, gsed 3.02a
 /RE/{x;s/$/This line is new/;G;}     # other seds
_

上記の2つの例は、コンソールから入力される「1行の」コマンドとして意図されています。 sedスクリプトを使用する場合、_i\_の直後にリテラル改行が続く場合、sedのすべてのバージョンで機能します。さらに、コマンド_s/$/This line is new/_は、ホールドスペースが既に空である場合にのみ機能します(デフォルトでは空です)。

正規表現に一致する各行の後に_This line is new_を追加するには:

_ /RE/a This line is new               # HHsed, sedmod, gsed 3.02a
 /RE/{G;s/$/This line is new/;}       # other seds
_

正規表現に一致する各行の後に2つの空白行を追加するには:

_ /RE/{G;G;}                    # assumes the hold space is empty
_

正規表現に一致する各行を5つの空白行に置き換えるには:

_ /RE/{s/.*//;G;G;G;G;}         # assumes the hold space is empty
_

(f)可能であれば_y///_コマンドを使用します:

一部のUnixバージョンのsed(GNU sed!)ではありません)、_s///_コマンドはRHSの_\n_を受け入れませんが、_y///_コマンドUnixのsedでサポートされている場合、aaaの後に改行を挿入できます(GNU sedまたは他のsedに移植性がありません):

_ s/aaa/&~/; y/~/\n/;    # assuming no other '~' is on the line!
_
60
przemoc

any POSIX互換sed(macOSのFreeBSDバージョンを含む)で動作する単一行ソリューション、/ =-シェルを想定bashまたはkshまたはzsh

_sed 's/\(1234\)/\'$'\n''\1/g' <<<'test1234foo123bar1234'
_

could single ANSI C-quoted string as the entire sedスクリプト、_sed $'...' <<<_、ただし_\_-はすべての_\_インスタンスをエスケープする必要があります(それらを2倍にする)。これは @ tovk's )と答えてください。

  • _$'\n'_は改行を表し、ANSI C quotingのインスタンスです。これにより、制御文字エスケープシーケンスを使用して文字列を作成できます。
  • 上記の splices ANSI Cで引用された文字列 into sed scriptは次のとおりです。 ____。]
    • スクリプトは、単純にを2つのシングルクォート文字列に分割し、ANSI Cクォート文字列を2つの半分の間に挟みます
    • 's/\(1234\)/\'は前半です。次の文字として挿入される改行をエスケープするために、は_\_で終わることに注意してください。 (このエスケープは、コマンドの終わりとして解釈されるのではなく、置換文字列の一部として改行をマークするために必要です)。
    • _$'\n'_は、ANSI Cで引用された改行文字の表現です。シェルは、スクリプトをsedに渡す前に actual 改行に展開します
    • _'\1/g'_は後半です。

このソリューションは、タブ文字を表す_$'\t'_などの他の制御文字に対しても同様に機能することに注意してください。


背景情報

  • POSIX sed仕様: http://man.cx/sed
    • [〜#〜] bsd [〜#〜] sed(macOSでも使用)はこの仕様に近いままで、 [〜#〜 ] gnu [〜#〜] sedは多くの拡張機能を提供します。
  • [〜#〜] gnu [〜#〜] sed [〜#〜] bsd [〜#〜の違いの概要] sedhttps://stackoverflow.com/a/24276470/45375 にあります
20
mklement0

sedのsolarisバージョンは、この方法で(bashで)動作することを確信できました。

echo test1234foo123bar1234 | sed 's/\(1234\)/\
\1/g'

(バックスラッシュの直後に改行を挿入する必要があります)。

cshにもう1つバックスラッシュを挿入する必要がありました。

echo test1234foo123bar1234 | sed 's/\(1234\)/\\
\1/g'

sedのGnuバージョンは、単に\n

echo test1234foo123bar1234 | sed 's/\(1234\)/\n\1/g'
8
bmk

Perlは、ここで役立つ、より充実した「拡張」正規表現構文を提供します。

Perl -p -e 's/(?=1234)/\n/g'

は、「パターン1234に続くゼロ幅一致の代わりに改行を使用する」ことを意味します。これにより、後方参照を使用して式の一部をキャプチャして繰り返す必要がなくなります。

8
Phil

残念ながら、私にとっては、sedは置換文字列の\nsを無視するようです。

$ echo test1234foo123bar1234 | sed "s/\(1234\)/\n\1/g"
testn1234foo123barn1234

それがあなたのために同様に起こる場合、代わりは使用することです:

$ echo test1234foo123bar1234 | sed "s/\(1234\)/\\`echo -e '\n\r'`\1/g"

これはどこでも動作するはずで、以下を生成します:

test
1234foo123bar
1234

入力としてinput.txtファイルを使用し、出力としてoutput.txtファイルを使用する例では、次を使用します。

$ sed "s/\(1234\)/\\`echo -e '\n\r'`\1/g" input.txt > output.txt
2
rid

これを試して:

$ echo test1234foo123bar1234 | sed "s/\(1234\)/\n\1/g"
test
1234foo123bar
1234

From Sed Gnu doc

g
    Apply the replacement to all matches to the regexp, not just the first. 
1
Fredrik Pihl

Bashの$'string'機能も使用できます。

man bash | less -p "\\$'"

printf  '%s' 'test1234foo123bar1234'  | sed $'s/\\(1234\\)/\\\n\\1/g'
1
tovk

コマンドの途中の改行は少し不器用に感じることがあります。

$ echo abc | sed 's/b/\
/'
a
c

以下に、この問題に対する2つの解決策を示します。これらは非常に移植性が高いはずです(POSIX準拠のshprintf、およびsedで機能するはずです)。

解決策1:

ここでprintf\および%文字をエスケープすることを忘れないでください:

$ echo abc | sed "$(printf 's/b/\\\n/')"
a
c

printf\および%文字をエスケープする必要を回避するには:

$ echo abc | sed "$(printf '%s\n%s' 's/b/\' '/')"
a
c

解決策2:

次のような改行を含む変数を作成します。

newline="$(printf '\nx')"; newline="${newline%x}"

またはこのように:

newline='
'

次に、次のように使用します。

$ echo abc | sed "s/b/\\${newline}/"
a
c
1