水底

ScalaとかC#とかネットワークとか

sh・bash・zsh等, shellの違いでハマりやすい部分とか

前提として

sh の実体は環境によって POSIX互換bash (bash --posix) であったり, dash であったり, busybox であったりと様々である (ls -l `which sh` とすれば実体がわかる). 唯一の制約は POSIX互換であること だ (※どこぞの今はなきお行儀が悪いOSを除けば). そのためシバンsh を利用する場合は, 最低限のPOSIX互換shell上で動作するように書かれるべき で, 例えば bash 拡張を用いる時はシバンbash を指定するべきだ. しかしながら, シバンsh を指定しているにも関わらずPOSIXの範囲を超えた命令を利用しても動いてしまうケースもままあり, 意識しないと難しい.

ハマりやすい差異の一例

空白 (正確には区切り文字) が含まれた変数

変数の展開され方が異なる

# bash, bash --posix, dash, busybox
: > 'a b'
x='a b'
mv $x c # error (`mv a b c` と解釈される)
ls # -> 'a b'
# zsh
: > 'a b'
x='a b'
mv $x c # (`mv 'a b' c` と解釈される)
ls # -> c

文字列の比較

== による文字列比較はPOSIX互換のものではない

# dash
[ 'a' = 'a' ] && echo 'ok' || echo 'ng' # -> ok
[ 'a' == 'a' ] && echo 'ok' || echo 'ng' # error -> ng
# zsh
[ 'a' = 'a' ] && echo 'ok' || echo 'ng' # -> ok
[ 'a' == 'a' ] && echo 'ok' || echo 'ng' # error
# bash, bash --posix, busybox
[ 'a' = 'a' ] && echo 'ok' || echo 'ng' # -> ok
[ 'a' == 'a' ] && echo 'ok' || echo 'ng' # -> ok

プロセスリダイレクト

これは bashzsh 固有の機能の一つ

# bash --posix, dash, busybox
cat <(echo 'a') # error
# bash, zsh
cat <(echo 'a') # -> a

結論

shellは方言や実装で微妙に違うところが多すぎて厳しい