このブログははてなブログからの移行記事です。
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