Solaris における sh builtin な echo の挙動

Solaris において,#!/bin/shシェルスクリプト内で,絶対パス指定無しの echo を使った場合の挙動の話.

背景

Solaris (SunOS) には System V 系のコマンド群と BSD 系のコマンド群の両方が含まれている.
これらのコマンドの挙動は大きく異なり,例えば echo コマンドで行末改行無しで hoge と出力したい場合,
System V 系では echo 'hoge\c' とし,BSD 系では echo -n hoge とする.
(bash builtin な echo はデフォルトで BSD 系.ただし,echo -e とすると System V 系の動作にも対応する (-e と -n は併用できる))

また,SunOS 4.x (Solaris 1.x) 以前と Solaris 2.0 (SunOS 5.0) 以降はベース OS が異なる.
SunOS 4.x 以前は BSD ベース.Solaris 2.0 以降は System V ベース.

結論

Solaris 2.0 以降の場合

環境変数 PATH において /usr/bin (/bin) と /usr/ucb のどちらが先に登録されているかによって挙動が変わる.
/usr/bin が先の場合,System V 系の挙動になる (/usr/bin/echo や /bin/echo と同じ挙動).
/usr/ucb が先の場合,BSD 系の挙動になる (/usr/ucb/echo と同じ挙動).

ただし,これは PATH で検索された echo コマンドを sh builtin な echo として使用しているという意味ではない.
反証として,PATH=$HOME/bin:/usr/bin:/usr/ucb な環境下で,$HOME/bin/echo を /usr/bin/echo と /usr/ucb/echo の好きな方に切り替えても,
切り替えは反映されず,純粋に PATH における /usr/bin と /usr/ucb の登録順で挙動が変わる.
 (PATH を文字列的に解析して挙動を切り替えていると考えられる)

Solaris 10 における検証結果を後述する.

SunOS 4.x 以前の場合

環境変数 PATH において /usr/bin と /usr/5bin のどちらが先に登録されているかによって挙動が変わる.
/usr/bin が先の場合,BSD 系の挙動になる.
/usr/5bin が先の場合,System V 系の挙動になる.

検証できる環境が無かったため,公式 (Oracle) のドキュメントを引用する.

検証

Solaris 10 における検証結果は下記の通り.

シェルスクリプト
cat test-sh-echo.sh
#!/bin/sh

echo /bin
PATH=/bin:/usr/ucb:/usr/bin
export PATH
which echo
echo -n hoge
echo "fuga\c"

echo; echo
echo /usr/bin
PATH=/usr/bin:/usr/ucb:/bin
export PATH
which echo
echo -n hoge
echo "fuga\c"

echo; echo
echo /usr/ucb
PATH=/usr/ucb:/bin:/usr/bin
export PATH
which echo
echo -n hoge
echo "fuga\c"

echo; echo
echo ~/bin, /bin
PATH=~/bin:/bin:/usr/ucb:/usr/bin
export PATH
which echo
ls -l $HOME/bin/echo  # $HOME/bin/echo -> /usr/ucb/echo
echo -n hoge
echo "fuga\c"

echo; echo
echo ~/bin, /usr/ucb
PATH=~/bin:/usr/ucb:/bin:/usr/bin
export PATH
which echo
ls -l $HOME/bin/echo  # $HOME/bin/echo -> /usr/ucb/echo
echo -n hoge
echo "fuga\c"
/bin/sh の場合

・PATH において /bin や /usr/bin が先の場合,System V 系の挙動.
・PATH において /usr/ucb が先の場合,BSD 系の挙動.
・PATH において $HOME/bin が最速でも,$HOME/bin/echo の挙動には左右されない.

% ./test-sh-echo.sh
/bin
/bin/echo
-n hoge
fuga

/usr/bin
/usr/bin/echo
-n hoge
fuga

/usr/ucb
/usr/ucb/echo
hogefuga\c


~/bin, /bin
/home/user1/bin/echo
lrwxrwxrwx   1 user1 user1       13 Dec 18 00:00 /home/user1/bin/echo -> /usr/ucb/echo
-n hoge
fuga

~/bin, /usr/ucb
/home/user1/bin/echo
lrwxrwxrwx   1 user1       13 Dec 18 00:00 /home/user1/bin/echo -> /usr/ucb/echo
hogefuga\c
%
/bin/bash の場合

シェルスクリプトのシェバングのみを /bin/bash に変更して実行.
・全てのケースにおいて BSD 系の挙動.

% ./test-bash-echo.sh
/bin
/bin/echo
hogefuga\c


/usr/bin
/usr/bin/echo
hogefuga\c


/usr/ucb
/usr/ucb/echo
hogefuga\c


/home/user1/bin, /bin
/home/user1/bin/echo
lrwxrwxrwx   1 user1 tornado       13 Dec 18 00:00 /home/user1/bin/echo -> /usr/ucb/echo
hogefuga\c


/home/user1/bin, /usr/ucb
/home/user1/bin/echo
lrwxrwxrwx   1 user1       13 Dec 18 00:00 /home/user1/bin/echo -> /usr/ucb/echo
hogefuga\c
%

公式 (Oracle) のドキュメント

Solaris 移行ガイド → 付録 A コマンドリファレンス

http://docs.oracle.com/cd/E19620-01/805-5828/6j5ggprcb/ (Solaris 2.6)
http://docs.oracle.com/cd/E19455-01/806-2724/6jbu1b2cg/ (Solaris 7)

SunOS 4.x から Solaris 2.6 や Solaris 7 への移行について記載されている.
表から話題に関係する行/列の記載のみ抜粋.
スペースの都合で Solaris 2.6 と Solaris 7 の記載を併記.
明らかな誤植は修正.

SunOS 4.x コマンド : sh(1)
利用可能な代替コマンドと注 :
[Solaris 2.6] SunOS 4.x では、組み込みコマンド echo および test の動作は、環境変数 PATH における /usr/bin と /usr/5bin との相対的な位置に依存する。現在では /usr/ucb と /usr/bin の相対的な並び換えによって動作が決まる。
[Solaris 7] SunOS 4 では、組み込みコマンド echo および test の動作は、環境変数 PATH における /usr/bin と /usr/5bin との相対的な位置に依存する。現在では /usr/ucb と /usr/bin の相対的な並び換えによって動作が決まる。

SunOS 4.x コマンド : echo(1V)
利用可能な代替コマンドと注 :
[Solaris 2.6] -n オプションは SunOS 4.x では改行を抑止した。SunOS 5.6 では \c を使用する。
[Solaris 7] -n オプションは SunOS 4 では改行を抑止した。SunOS 5.7 では \c を使用する。