このブログははてなブログからの移行記事です。
8/9(日) @bataさんにご指摘いただいて追記しました!
研修でこれから書く予定のWebアプリの開発環境がCentOS7なのでそれに合わせてしこしこdotfilesを書いて、つい先日完成させた。
それを手元のMacで動かしたところ、インストールコマンドのechoの挙動がおかしかったので直した(今は直ってます)。
直す前
インストールにそれっぽさを出すため、何をしてるかを色付きで出力していた(本当に簡易だが…)

一色だと寂しいし複数色にできるようにしてそれっぽさ醸し出そうと思って手元で./install叩いたらこうなった。

色がつかず、色をつけるためのエスケープシーケンスどころかechoの-eオプションまで出力されてしまっている。コマッタ。
修正方法
とりあえずいろいろ調査してみる。
Shellでecho -eを叩くとどうなるか
そもそも-eオプションはエスケープシーケンスを出力しないためのもの。
適当に叩いてみるとこうなる。

うん、大丈夫。
絶対パスでecho -eを叩く
なぜか/bin/echo -eすると以下のような結果になり、Shellscriptの時と同じ現象に陥る。

エー…
試しに以下のようなShellファイルを作って試す。
which echo echo -e "hello"
んで以下の様に実行するとこうなる。

あれ、built-in commandじゃなくなってる。
ここで気づく。Shellscriptを実行してるのはshだけど今の僕のShellはzsh。
てことでzshで同じファイルを実行してみる。

動いたーーーー
試しにbashでも実行してみる。

え、shも/bin/echoを実行してたのにbashだと動いてる…意味不明…
結果
表でまとめてみるとこんな感じになってる。
| 実行シェル | which echo |
-eオプションは有効か |
|---|---|---|
sh |
/bin/echo |
無効 |
bash |
/bin/echo |
有効 |
zsh |
shell built-in command | 有効 |
zshはビルトインコマンドだから動くとして、shとbashで挙動が違うのがマジで謎だ…困った。
結局どうしたか
結論としてはechoの替わりにprintfを使うことにしました。
ggってみるといくらかの人たちが同じようなことで困っていました。
この状態でechoの-eオプション使うと実態わからないまま環境ごとに切り分けなきゃいけなくなって気持ち悪いけど、printfを使えばどの環境でもおおよそ同じ動きをするのでこちらを採用しました(色つけるのにオプションも必要ないしね)。
てことで
Before
echo -e "\e[34m$*\e[m"
After
printf "\033[34m$*\033[0m\n"
って感じになりました。
めでたしめでたし。
まとめ
- OS Xでの
echoの-eオプションの挙動がアクロバティック -eオプションを使う理由が色付き出力であればprintfを活用すべし
echo周りの謎は答えがわかったらまた記事書きます!もしくは誰か調べてく(ry
追記
@bataさんより以下のようなご指摘をいただきました。
@sota1235 shでechoするとビルトイン優先.whichは通常PATHから探すだけなのでそもそも検証が無意味.でビルトインechoはshとbashで実装が違ってshのは-eを解釈しない.strace -fiv sh -c 'echo -e hello'とかするとわかるよ
— bata (@bata_24) 2015, 8月 7
そもそもwhichコマンドで検証した時点でミスしていたようです。
無知がゆえにstraceコマンドの結果をすぐに記事にできるほど理解できないので取り急ぎ(また追記します( ꒪⌓꒪))
COMMENT: ご指摘ありがとうございます、試してみたら全て組み込みコマンドでした! COMMENT: bashもシェル組込みコマンドでは? $ type echo echo is a shell builtin