シェルスクリプトにシバン(#!/bin/sh)はないほうがいいという説

職場のパソコンで作業用にシェルスクリプトを書いていた。PATH変数の初期化に使っていたgetconfコマンドがないことを発端に,getconfのない環境でのPATH変数の初期化から,Androidで動くシェルスクリプトについて議論が発展した。 その中で,Androidでも動くシェルスクリプトを書くためには,シバン(#!/bin/sh)を書いてはいけないという結論が得られた。 一連の議論を記録として残す。 続きを読む
10

Togetter投稿

. @senopen

「シェルスクリプトにシバン(#!/bin/sh)はないほうがいいという説」をトゥギャりました。 togetter.com/li/1077808

2017-02-04 17:32:05
. @senopen

まとめを更新しました。 シバンがない場合,cshの対話シェルから起動されたら,shで再起動するにして,対応できたので,その話とサンプルコードを掲載。「シェルスクリプトにシバン(#!/bin/sh)はないほうがいいという説」 togetter.com/li/1077808

2017-02-25 13:19:41
. @senopen

まとめを更新。cshの問題が解決。 これにより,Androidでもcshでも,文字エンコーディングにBOMがあっても動作する,より可搬性の高いシェルスクリプトの記述方法がみつかった。「シェルスクリプトにシバン(#!/bin/s.. togetter.com/li/1077808

2017-03-30 23:05:39

発端

会社のNASサーバーでデータ処理をするためにシェルスクリプトを書いて試していたら,以下のPATH変数の初期化で getconf コマンドが見つからないというエラーが出ていた。

export LC_ALL='C' PATH="$(command -p getconf PATH):$PATH"
. @senopen

会社のサーバーパソコン。ディストリビューション不明なのだけど、なんとgetconfがなかった。PATH変数の初期化でスクリプトが落ちていた。 えー。getconfないとかいったいどうしたらいいんだ…

2017-02-01 15:22:58
. @senopen

@senopen unamw -aするとarmとかsmpとか表示された。なんだろう?こんなディストリビューションあるの?帰宅したら調べてみよう。

2017-02-01 16:03:51
リッチー大佐の中の人 @col_richie

@senopen /etcの中にissueとかos-releaseとかというファイルがあったりしないだろうか。それからarmやsmpとはCPU構成のことではないだろうか。ARMのマルチコアとか……。

2017-02-01 17:00:08
. @senopen

@col_richie os-releaseはなく、issueは以下の内容でした。 welcome to TS-231+, QNAP Systems, Inc。なんかベンダー独自ディストリビューションなのでしょうか。始めてみました。

2017-02-01 17:19:21
リッチー大佐の中の人 @col_richie

@senopen 製品は qnap.com/ja-jp/product/… で(なるほど確かにarm smp)、OSは qnap.com/event/qts/jp/?… か……。 他にもPOSIX非準拠な点が多数あれば、そもそも準拠する気がない製品として無視してもよいかも。

2017-02-01 18:09:28
リッチー大佐の中の人 @col_richie

@senopen もしかしてコマンドやシェルがBusyBox(コマンドが全て1つの実行ファイルへのハードリンク)になっていないだろうか。もしそうだったらさすがにPOSIX原理主義でも救いきれない。

2017-02-01 18:15:39
. @senopen

@col_richie busybox使ってました。findとかreadlinkとかgrep, awk, sedなどなど。shはbashでした。busyboxはあまりPOSIX準拠してないのでしたっけ?調べないとわかりませんね…

2017-02-01 18:24:47
リッチー大佐の中の人 @col_richie

@senopen あぁやっぱり。BusyBoxは、UNIXであることよりも、貧弱な組み込み環境でも必要最低限のことができることを優先しているので容赦なくPOSIX仕様を満たさないからなぁ。 BusyBoxで使えるコマンドはこちら→ busybox.net/downloads/Busy…

2017-02-01 18:29:35
. @senopen

@col_richie げ!なんと!うーん。困りましたね… busybox採用している環境はそれなりにありそうなので、何のコマンドがどう準拠していないのか、把握しておいたほうがいい気がしますね…

2017-02-01 18:35:16
リッチー大佐の中の人 @col_richie

@senopen BusyBoxの大半はPOSIXのサブセットなのでPOSIX原理主義のサブセット的な主義を立ち上げるという考えもあれど、その制約を緩和するためにGNU coreutilsコマンドの一部が入ってもいるので、結局BusyBoxはBusyBoxで独自の主義が要るかと…

2017-02-01 18:42:15
. @senopen

@col_richie 独自の主義は不要と考えてます。 1. POSIXの定義が全てが常に有効というわけでもない 2. POSIX定義コマンドの全代替実装を把握したわけではない POSIXの乖離性がどれほどあるかわかりませんが,手間でなければBusyBoxをカバーしてもいいかなと

2017-02-01 22:33:21

getconfが存在しない場合のPATH変数の初期化方法

実際にgetconfが存在しない環境がみつかった。サーバーなどパッケージングが厳選されているディストリビューションではgetconfコマンドが存在しないことはありえる。
こうした環境でもエラーが出ないようにコードの工夫を試みた。

. @senopen

ええーい。getconfがない場合でもうまくケアしたPATH変数の初期化方法はないものか。 なんとかうまくできないだろうか。あまり長ったらしくなく,やる方法だ。 こんな感じでどうだろうか? command -p $(command -v getconf || :) PATH

2017-02-01 22:53:42

zsh対応

getconfが存在しない環境をケアした初期化方法は思いついたが,zshで動作しないという問題が生じた。

. @senopen

間違えた。こうやったら一応動く。 command -p $(command -v getconf || echo :) PATH でもzshだとcommand -p :がnot found。意味不明。

2017-02-01 22:59:36
. @senopen

command -pって組み込みコマンドはダメなんだったっけ? -pオプション無しでもzshだとだめだ。 あれか。zshはPOSIX互換のオプションを有効にしないとアカン感じか。man zshmiscのcommandのヘルプ見たらexternal commandって書いてあった。

2017-02-01 23:05:09
. @senopen

どうする?/bin/shの実体がzshなことってありえるのか?考慮すべきなのか?考慮する場合は,:をtrueに変えれば事足りるけど。

2017-02-01 23:17:53
. @senopen

zshを考慮して完璧なPATH変数の初期化をやるなら。こうなる。 export PATH="$(command -p $((command -v getconf || echo true) | sed 's@.*/@@') PATH):$PATH" 1行に入りきらんぞ…どうしよう

2017-02-01 23:19:14
. @senopen

command -pで絶対パスを指定してしまうと,そのパス指定が優先されてしまう。Solarisで結果が変わる。コマンド名だけだと,/usr/xpg6/binをみるけど,command -vだと/usr/xpg4/binをみにいってしまう。だから最後にsedで/を削除した。

2017-02-01 23:21:50
1 ・・ 10 次へ