web-dev-qa-db-ja.com

Mac OS Xのsedの改行

見つけた \nはMac OS Xのsedでは機能しません。具体的には、1つのスペースで区切られた単語を行に分割したいとします。

# input
foo bar

私が使う、

echo "foo bar" | sed 's/ /\n/'

しかし、結果は愚かです、\nはエスケープされていません!

foonbar

私はグーグルに相談した後、私は 回避策 を見つけました:

echo 'foo bar' | sed -e 's/ /\'$'\n/g'

記事を読んでも、何が理解できないのか\'$'\n/g' 手段。誰かがそれを私に説明できますか、それとも他に方法がありますか?ありがとう!

46
Ivan Z. G. Xiao

あなたはできる brew install gnu-sedsedの呼び出しをgsedに置き換えます。


sedの代わりにgsedとして使用するには、インストール後にbrewが次の指示を出力すると便利です。

GNU "sed" has been installed as "gsed".
If you need to use it as "sed", you can add a "gnubin" directory
to your PATH from your bashrc like:

    PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"

つまり、次の行を〜/ .bashrcまたは〜/ .zshrcに追加します。

export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"
30
Ahmed Fasih

これらも機能します:

echo 'foo bar' | sed 's/ /\
/g'

echo 'foo bar' | sed $'s/ /\\\n/g'

lf=$'\n'; echo 'foo bar' | sed "s/ /\\$lf/g"

OS Xのsedは、置換パターンの\nを解釈しませんが、行継続文字が前に付いたリテラルラインフィードを使用できます。シェルは、sedコマンドが実行される前に、$'\n'をリテラルラインフィードに置き換えます。

25
Lri

見つかった回避策は、単一の引数文字列をsed -eに渡します。

その引数は、おなじみのsed s/ / /g形式の文字列になります。

その文字列は、2つの部分で次々に作成されます。

最初の部分は'...'形式で引用されています。

2番目の部分は$'...'形式で引用されます。

's/ /\'部分は、単一引用符を取り除いたものですが、それ以外は、コマンドラインで見たとおりに通過してsedに渡されます。つまり、バックスラッシュはbashに食べられず、sedに渡されます。

$'\n/g'の部分はドル記号と単一引用符を取り除いたもので、\nは改行文字に変換されます。

まとめると、議論は

s// \newline/ g

[それは楽しかった。それを解くのにしばらくかかりました。興味深い質問には+1。]

11
Spiff

$'...'bash- ismであり、標準のエスケープシーケンスを展開して...を生成します。 \'は、引用符で囲まれたセクションの最後にバックスラッシュが続くことを意味し、結果の文字列はs/ /\になります。 (はい、文字列の途中で引用符を切り替えることができます。文字列を終了するわけではありません。)

POSIX標準sedは、検索パターンの一部として\nのみを受け入れます。 OS XはFreeBSD sedを使用します。これはPOSIXに厳密に準拠しています。 GNUはいつものように余分なものを追加し、それからLinuxユーザーは皆、それはある種の「標準」だと思っています(どちらかが標準プロセスを持っていれば、もっと感銘を受けるでしょう)。

7
geekosaur

何が起こっているのかを視覚的に簡単に確認できます。単に文字列をエコーし​​ます!

echo 's/$/\'$'\n/g'

結果は

s/$/\
/g

これはs/$/\と同等ですnewline/g

newlineの前に余分な\がない場合、シェルはnewlineをコマンドの終わりとして途中で解釈します。

1
wisbucky

この回避策はMacで機能し、スクリプトはLinuxでも実行できます

NL="\n"
if [[ $uname -eq "Darwin" ]]; then
    NL=$'\\\n'
fi

echo 'foo bar' | sed -e "s| |${NL}|" 
0
Max Zerbini