調べたら有名な話らしいが, 一応備忘録として書いておく.
参考: https://stackoverflow.com/questions/36277870/zsh-why-is-n-interpreted-within-single-quotes
問題
最近 Bash から Zsh に乗り換えたのだが, 以下の様な動作の違いに遭遇し困惑した.
echo 'hoge\nfuga' を Bash と Zsh でそれぞれ実行すると
$ echo 'hoge\nfuga'
hoge\nfuga
$ echo 'hoge\nfuga'
hoge
fuga
となり, \n が改行文字として解釈されるか否かが異なる.
echo コマンドはオプション -e をつけない限り \n の様なエスケープシーケンスは解釈せずそのまま出力するものと理解していたため, Zsh は echo に渡す前に \n を改行文字に置き換えるのか? (シングルクオーテーションで囲っているのに?) などと混乱した.
解決
原因は echo の方にあった. type でそれぞれが呼んでいる echo が何なのかを調べると,
$ type echo
echo is a shell builtin
$ type echo
echo is a shell builtin
両者ともビルトインの echo を呼んでいる. しかしそれぞれのビルトインの仕様に差があるようだ.
マニュアル(Bash, Zsh)を読んでみると, (あまり明示的には書かれていないが文脈から考えると) Bash の方はデフォルトではエスケープシーケンスを解釈しない一方 Zsh は解釈するみたいだ.
Bash:
If the -e option is given, interpretation of the following backslash-escaped characters is enabled. The -E option disables the interpretation of these escape characters, even on systems where they are interpreted by default. The xpg_echo shell option may be used to dynamically determine whether or not echo expands these escape characters by default.
Zsh:
The -E flag, or the BSD_ECHO option, can be used to disable these escape sequences. In the latter case, -e flag can be used to enable them.
まとめ
echoコマンドの可搬性には気を付けましょう.