Mac OS Xではsedで\nが動作しないことがわかりました。具体的には、1つのスペースで区切られた単語を行に分割したいとします
# input
foo bar
I use,
echo "foo bar" | sed 's/ /\n/'
しかし、結果は馬鹿げていて、\nがエスケープされていません!
foonbar
googleに相談したところ、回避策を見つけました
echo 'foo bar' | sed -e 's/ /\'$'\n/g'
記事を読んでみても、\'$'\n/g'の意味がいまだにわかりません。誰か説明してくれないか、他の方法があれば教えてください。ありがとうございます
51 Ivan Z. G. Xiao 2011-07-06
brew install gnu-sedとsedの呼び出しをgsedに置き換えることができます
gsedではなくsedとして使用するには、インストール後に以下のような指示が表示されます
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"
33 Ahmed Fasih 2013-04-14
これらも効果があるでしょう
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' をリテラル改行で置き換えます
26 Lri 2011-07-07
見つけた回避策では、sed -eに1つの引数文字列を渡しています
この引数は、おなじみの sed s/ / /g 形式の文字列で終わります
その文字列は、次から次へと2つの部分に分けて作成されます
最初の部分は'...'形式で引用します
2番目の部分は$'...'形式で引用しています
's/ /\' の部分はシングルクォートが取り除かれますが、それ以外の部分はコマンドラインでの見た目と同じように sed に渡されます。つまり、バックスラッシュは bash に食べられず、sed に渡されます
$'\n/g'の部分はドル記号とシングルクォートが取り除かれ、\nは改行文字に変換されます
全てを合わせると、議論は次のようになります
s/ /\newline/g
(誠人の声) 「面白かったよ、解くのに時間がかかった
12 Spiff 2011-07-07
式 $'...' は bash-ism であり、標準のエスケープシーケンスを展開した ... を生成します。\' の前の \' はバックスラッシュと引用符で囲まれた部分の終わりを意味し、結果として得られる文字列は s/ /\ となります。(そう、文字列の途中で引用符を切り替えることができます。)
POSIX標準のsedは検索パターンの一部として\nだけを受け入れます。OS X は FreeBSD sed を使っていますが、これは POSIX に厳密に準拠しています。GNU はいつものように余分なものを追加して、Linux ユーザはそれをある種の「標準」だと思っています (たぶん、どちらかが標準化プロセスを持っていたら、私はもっと感銘を受けたでしょう)
7 geekosaur 2011-07-06
視覚的に見やすい工夫がある文字列をエコーするだけでOK!
echo 's/$/\'$'\n/g'
results in
s/$/\
/g
これはs/$/\newline/gに相当します
もし、newlineの前に余分な\がなければ、シェルはnewlineをコマンドの終了として解釈してしまいます
1 wisbucky 2017-10-27
この回避策はMacで動作し、Linuxでも実行できます
NL="\n"
if [[ $uname -eq "Darwin" ]]; then
NL=$'\\\n'
fi
echo 'foo bar' | sed -e "s| |${NL}|"
1 Massimo Zerbini 2020-03-10
@max-zerbiniの答えのもう少しコンパクトな形
[[ $(uname) -eq "Darwin" ]] && NL=$'\\\n' || NL="\n"
echo 'foo bar' | sed -e "s| |${NL}|"
0 slm 2020-06-03

