拡張 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 系の echo
は printf
で簡単に模倣することができます。
普段 BSD 系 echo
に慣れている、かつ -e
オプションを利用していないなら、
これを利用するのもありでしょう。
echo() {
if [[ $1 = -n ]]; then
shift
printf '%s' "$*"
else
printf '%s\n' "$*"
fi
}
echo
と違い、printf
コマンドの第一引数は %
によるフォーマット指定を解釈する点に注意してください。
スクリプト外部から得た文字列をそのまま第一引数に含めてしまうと、
フォーマット文字列攻撃を受ける可能性があります。
古い sh
や ksh
では printf
が組込みコマンドではありません。
エスケープシーケンス
ついでに System V 系 echo
または -e
オプション対応の BSD 系 echo
のエスケープシーケンスを紹介しておきます。
\a
- 警告文字 (ベル、0x07)
\b
- バックスペース (0x08)
\c
- 改行の抑制
- 実装に依ってはこれ以降の文字列を無視するため、最後に含めるのが無難。
\e
- エスケープ文字 (0x1B)
\E
- エスケープ文字 (0x1B)
- bash 組込み
echo
依存。
\f
- 用紙送り文字 (フォームフィード、0x0C)
\n
- 改行文字 (LF、0x0A)
\r
- 復帰文字 (CR、0x0D)
\t
- 水平タブ (0x09)
\v
- 垂直タブ (0x0B)
\\
- バックスラッシュ (0x5C)
\0
- ヌル文字 (NULL, 0x00)
\0NNN
- 8 進数 1〜3桁の 1バイトコード
\xNN
- 16 進数 1〜2桁の 1バイトコード
\uNNNN
- 16 進数 1〜4桁のユニコード 1文字のコード
- bash, zsh 組込み
echo
依存。
\UNNNNNNNN
- 16 進数 1〜8桁のユニコード 1文字のコード
- bash, zsh 組込み
echo
依存。
おまけ。
- sh・bash・zsh 他 echo 比較 - mattintosh note -hatena-
ところで、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 もどうぞ。
- Ansible Advent Calendar 2023
- シェル芸 Advent Calendar 2023
- 闇の魔術に対する防衛術 Advent Calendar 2023
- Ansible Advent Calendar 2023
- Ansible Advent Calendar 2020
- DNS温泉 Advent Calendar 2019
- OSSTech Advent Calendar 2019
- Ansible Advent Calendar 2018
- OSSTech Advent Calendar 2018
- Debian/Ubuntu Advent Calendar 2017
- Linux Advent Calendar 2017
- Shell Script Advent Calendar 2017
- Shell Script Advent Calendar 2016
- OpenLDAP と仲間たち Advent Calendar 2015
- Postfix Advent Calendar 2014
- 拡張 POSIX シェルスクリプト Advent Calendar 2013