echo コマンドの違いと移植性の問題 - 拡張 POSIX シェルスクリプト Advent Calendar 2013 - ダメ出し Blog

2013-12-08(Sun) [sh][shell] [更新履歴]

拡張 POSIX シェルスクリプト Advent Calendar 2013、8日目の記事です。

今日はシェルや OS ごとに微妙に異なる echo コマンドの違いを紹介します。 echo コマンドの挙動は大きく分けて 2種類あります。

BSD 系 echo コマンドの挙動

引数に指定された文字列をそのまま出力します。 複数の文字列が指定された場合はスペース (0x20) 一文字で区切られます。

最後に改行を出力しますが、最初の引数が -n のときはオプションとして認識し、 最後の改行を出力しません。

$ echo foo
foo
$ echo foo bar
foo bar
$ echo 'foo\nbar'
foo\nbar
$ echo foo; echo bar
foo
bar
$ echo -n foo; echo bar
foobar
$ echo 'foo\c'; echo bar
foo\c
bar

これに該当するのは bash の組込み echo、各種 Linux (GNU coreutils) や BSD 系 OS などの /bin/echo です。zsh も set -o BSD_ECHO 時には該当します。

echo コマンドの実装に依っては -e オプションを持つものがあります。 これを指定した場合、文字列に含まれる各種エスケープシーケンスを解釈してから出力します。 (bash、zsh, GNU coreutils)

System V 系 echo コマンドの挙動

引数に指定された文字列に含まれるエスケープシーケンスを解釈してから出力します。 複数の文字列が指定された場合はスペース (0x20) 一文字で区切られます。

最後に改行を出力します。 改行を抑制するオプションはありませんが、文字列に エスケープシーケンス \c が含まれている場合は改行は出力しません。

$ echo foo
foo
echo foo bar
foo bar
$ echo 'foo\nbar'
foo
bar
$ echo foo; echo bar
foo
bar
$ echo -n foo; echo bar
-n foo
bar
$ echo 'foo\c'; echo bar
foobar

これに該当するのは , zsh や dash の組込み echo、Solaris (System V 系の OS 各種) や AIX などの /bin/echo です。bash も shopt -s xpg_echo 時には該当します。

zsh の組込み echo は特殊で -n オプション(改行の抑制)と -E オプション(エスケープ文字の解釈の抑制)にも対応しています。 bash の echo-E オプションがあります。

ksh の組込み echo コマンド

ksh は特殊で、仕様は動作する OS の /bin/echo と同じになります。 このため、echo を利用している ksh スクリプトはポータビリティの問題が生じる可能性があります。

csh の組込み echo コマンド

csh? いえ、知らない子ですね。

ポータビリティ対策

シェルや OS の違いに依らないポータビリティ(移植性、可搬性) の高いシェルスクリプトを書くには、ポータビリティに問題がある echo を利用してはいけません。代わりに printf を利用しましょう。 shebang を #!/bin/sh にしていたとしても、/bin/sh の実体が何かは OS や設定に依るのでご注意を。

BSD 系の echoprintf で簡単に模倣することができます。 普段 BSD 系 echo に慣れている、かつ -e オプションを利用していないなら、 これを利用するのもありでしょう。

echo() {
  if [[ $1 = -n ]]; then
    shift
    printf '%s' "$*"
  else
    printf '%s\n' "$*"
  fi
}

echo と違い、printf コマンドの第一引数は % によるフォーマット指定を解釈する点に注意してください。 スクリプト外部から得た文字列をそのまま第一引数に含めてしまうと、 フォーマット文字列攻撃を受ける可能性があります。

古い shksh では printf が組込みコマンドではありません。

エスケープシーケンス

ついでに System V 系 echo または -e オプション対応の BSD 系 echo のエスケープシーケンスを紹介しておきます。


おまけ。


ところで、12月25日はクリスマスな上に、 OSS 界隈で地味に活躍されているふみやすさんの誕生日ですね!
http://www.amazon.co.jp/registry/wishlist/27M7TV8CEEF6G?sort=priority

逆に、あなたの書いた OSS や Blog や Advent Calendar が気に入ったら何か送りたく なってしまうかもしれないので、プロフィールや Web サイトに あなたの Amazon 欲しいものリストの URL を貼っておいてくださいね!


私が勤める OSSTech っていう某弊社で社員募集しているようです。 人材紹介会社を介さなければ、入社後に 20万円のボーナス! 「ふみやすっていう人に紹介された」と言ってもらえると私にもボーナス!! → https://www.osstech.co.jp/recruit/


よろしければ、これまで参加した/参加予定のほかの Advent Calendar もどうぞ。