ISUCONの練習でnetdataのinstallシェルスクリプトを書いていたらshとbashの違いでハマったので、忘備録として残していきます。
問題
#!/bin/bash ... bash <(curl -Ss https://my-netdata.io/kickstart.sh) --no-updates --dont-wait --stable-channel --disable-telemetry
上記のシェルスクリプトをsh setup.sh
で実行したところ、以下のように途中でエラーが吐かれてしまいました。
$ sh setup.sh ... setup.sh: line 27: syntax error near unexpected token `(' setup.sh: line 27: `bash <(curl -Ss https://my-netdata.io/kickstart.sh) --no-updates --dont-wait --stable-channel --disable-telemetry'
原因
netdataのinstallに利用していた<(
は、process substitiionというbashの機能だったため、shコマンドでシェルスクリプトを実行するとこの機能が使えないことが原因でした。
RedHat系のLinuxでshコマンドをlsでみてみると、bashのシンボリックリンクになっています。
$ ls -l /bin/sh lrwxrwxrwx 1 root root 4 Jul 21 2020 /bin/sh -> bash
一見するとshとbashコマンドで同じ挙動を取るように見えますが、実際はshコマンドをデフォルトの設定のまま使うとPOSIXモードが有効になっているため、bashの機能が使えません。 bashの設定を見てみると以下のようにposixがoffになっています。
$ bash $ set -o ... posix off ...
一方でshの設定を見てみるとposixがonになっています。
$ sh $ set -o ... posix on ...
今回のケースでは、shコマンドでシェルスクリプトを実行したため、POSIXモードがonになり、process substitionが使えずエラーになっていました。
sh setup.sh
ではなくbash setup.sh
とすることで無事エラーにならずセットアップ スクリプトを実行することができました。
参考
shell - Difference between sh and bash - Stack Overflow
/bin/shと/bin/bashの違い(とcronでのシェル)