見つけた \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'
手段。誰かがそれを私に説明できますか、それとも他に方法がありますか?ありがとう!
あなたはできる brew install gnu-sed
とsed
の呼び出しを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"
これらも機能します:
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'
をリテラルラインフィードに置き換えます。
見つかった回避策は、単一の引数文字列をsed -e
に渡します。
その引数は、おなじみのsed s/ / /g
形式の文字列になります。
その文字列は、2つの部分で次々に作成されます。
最初の部分は'...'
形式で引用されています。
2番目の部分は$'...'
形式で引用されます。
's/ /\'
部分は、単一引用符を取り除いたものですが、それ以外は、コマンドラインで見たとおりに通過してsedに渡されます。つまり、バックスラッシュはbashに食べられず、sedに渡されます。
$'\n/g'
の部分はドル記号と単一引用符を取り除いたもので、\n
は改行文字に変換されます。
まとめると、議論は
s// \newline/ g
[それは楽しかった。それを解くのにしばらくかかりました。興味深い質問には+1。]
式$'...'
はbash
- ismであり、標準のエスケープシーケンスを展開して...
を生成します。 \'
は、引用符で囲まれたセクションの最後にバックスラッシュが続くことを意味し、結果の文字列はs/ /\
になります。 (はい、文字列の途中で引用符を切り替えることができます。文字列を終了するわけではありません。)
POSIX標準sed
は、検索パターンの一部として\n
のみを受け入れます。 OS XはFreeBSD sed
を使用します。これはPOSIXに厳密に準拠しています。 GNUはいつものように余分なものを追加し、それからLinuxユーザーは皆、それはある種の「標準」だと思っています(どちらかが標準プロセスを持っていれば、もっと感銘を受けるでしょう)。
何が起こっているのかを視覚的に簡単に確認できます。単に文字列をエコーします!
echo 's/$/\'$'\n/g'
結果は
s/$/\
/g
これはs/$/\
と同等ですnewline/g
newline
の前に余分な\
がない場合、シェルはnewline
をコマンドの終わりとして途中で解釈します。
この回避策はMacで機能し、スクリプトはLinuxでも実行できます
NL="\n"
if [[ $uname -eq "Darwin" ]]; then
NL=$'\\\n'
fi
echo 'foo bar' | sed -e "s| |${NL}|"