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

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

あとは,toyboxとか。似たようなのが他にもあるかもしれない。 BusyBoxのshellはash。環境を手元に用意しておいたほうがいいか。 What is toybox? landley.net/toybox/about.h…

2017-02-02 21:32:15
. @senopen

Androidには標準で/system/bin/にtoolboxというbusyboxみたいなのが入っているのか。しらなかった… toolbox ‐ 通信用語の基礎知識 wdic.org/w/TECH/toolbox

2017-02-02 22:04:20

PATHの初期化決着

以下のように2段階でやれば解決

PATH="$(command -p getconf PATH 2>&-):/bin:/usr/bin${PATH:+:}${PATH:-}"
export PATH=${PATH#:}
. @senopen

@senopen busyboxのashでもcommand -pvが使えるか試したら、ダメだった。帰宅したらkshとかでも念のため確認してみるか… command -pvはやめたほうがいいのだろうか…

2017-02-03 09:26:59
リッチー大佐の中の人 @col_richie

@senopen ashはFreeBSDの/bin/shでもあるので、FreeBSDでも試してみたところ、 $ command -pv getconf PATH command: wrong number of arguments $ となり、通じないOSがさらに一つ確認された

2017-02-03 10:08:25
リッチー大佐の中の人 @col_richie

@senopen ksh88(AIXの/bin/sh)で同じコマンド実行したら、 sh: command: bad option(s) と表示されて失敗した。ksh93(AIX)とpdksh(ksh93ベースのOpenBSDの/bin/sh)では成功した。

2017-02-03 10:36:26
. @senopen

@col_richie 調査ありがとうございました。 さすがに影響範囲が広いので無視できませんね。幸いなことに、command -pvを使わずにgetconfがあれば実行してPATHを取得する最短記述方法が思いついたので大丈夫そうです。昼休みに続きを書きます。

2017-02-03 10:57:58
くらげ採り網 @kuragegge

せのぺんさんとリッチー大佐が頑張ってる

2017-02-03 10:58:13
. @senopen

以下のように常にエラーを無視すれば大丈夫です。 ついでにgetconfのない環境用に、/bin:/usr/binを追加。 export PATH="$(command -p getconf PATH 2>&-):/bin:/usr/bin:$PATH" @col_richie

2017-02-03 12:21:03
リッチー大佐の中の人 @col_richie

@senopen /bin:/usr/binを付けることに確固たる理由づけが欲しいところだなぁ。

2017-02-03 14:13:25
. @senopen

@col_richie 根拠はFHS。sbinはシステム管理者用コマンドなので不要だと判断。 この先、androidやiOS対応もするなら、シバン#!/bin/shと一緒に外します。シバンの根拠がFHSなので、シバンをつけるなら、一緒につけても問題ないと判断しました。どうでしょう

2017-02-03 14:21:31
リッチー大佐の中の人 @col_richie

@senopen なるほど、それなら説明がつくな。>FHS そういえばPATH文字列の中に、空パス(":〜"や"〜::〜"や"〜:")とか存在しないパスが指定されていても正しく動くことは保証されているかな?まぁ動かない事例は聞いたこともないし、動かない環境の方が非実用的に思えるし

2017-02-03 14:31:44
. @senopen

@col_richie 空パスの扱いについては、XBDのenvironmenral variableのPATHの説明で書いてあった記憶があります。帰宅したら確認してみます。

2017-02-03 14:34:28
リッチー大佐の中の人 @col_richie

@senopen XBDのその場所を読んだところ、空パス(ずばり":〜"や"〜::〜"や"〜:"を示している)は、カレントディレクトリーと見なすらしい。うーむ、これは厄介。

2017-02-03 14:46:46
リッチー大佐の中の人 @col_richie

@senopen 空パス問題解決方法。 PATH="$(command -p getconf PATH 2>&-):/bin:/usr/bin${PATH:+:}${PATH:-}" export PATH=${PATH#:} というように、二段階にすると何とか解決できる事を発見

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

@senopen ${PATH:+:}というのが最初の工夫。":+"は元変数が未定義または空の場合に空文字を返すが何か入っていれば":"を返す。つまりPATHに何か入っていれば、元のPATHの中身の手前に$(〜)を付け足す時に自動的に":"が付くという。次の工夫は二段目の"#:"

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

@senopen しかし、だいぶ長ったらしくなってしまうなぁ。

2017-02-03 16:47:41
. @senopen

@col_richie うまいですね!なるほど。:+はおもいつきませんでした。素直にsedを考えていました。 既存のPATHに含まれる、空:や., ./もカバーすべきなんでしょうかね…だとしたら結局sedが必要で、長くなってしまいますが…。

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

@senopen 既存の$PATHに入っているものはそのままでいいのではないかなぁ。こちらのプログラムが必要としているパスは手前に付けてしまうし、元々空パスついていれば意図的なのかそうでないか判断する術もないし、sedも必要になってしまうし……

2017-02-03 21:10:52
. @senopen

@col_richie ああ。そうでしたね。安全なPATHを前置しているから,既存のPATHがどうなっていようが大丈夫という論理でしたね。お騒がせしました。

2017-02-03 21:45:55

PATH初期化についての懸念

. @senopen

FHSの/sbinのコマンドがPOSIXに入っていないか確認したのだけど,なかった。 PATHの初期化時に入れるのはやめたほうがいいか。 Filesystem Hierarchy Standard refspecs.linuxfoundation.org/FHS_3.0/fhs-3.…

2017-02-04 16:18:19
. @senopen

PATH変数の初期化。自分で/bin:/usr/binを入れたほうがいいと書いたけど,これ入れると,${PATH#:}が必要になり2行。 export LC_ALL='C' PATH="$(command -p getconf PATH 2>&-)${PATH:+:}$PATH"

2017-02-04 16:33:48
. @senopen

いらないなら上記のように1行で全部書ける。コードの綺麗さで行くとこっち。だけど,getconfがないとPATHの初期化ができなくて危険。 Androidも対応するなら,長くなるからPATH変数の初期化でもう1行追加して,/usr/local/binも追加して3行でもいいのだけど…

2017-02-04 16:36:22
. @senopen

こう PATH="/bin:/usr/bin:/usr/local/bin:/sbin:/system/bin${PATH:+:}$PATH" PATH="$(command -p getconf PATH 2>&-):$PATH" export PATH="${PATH#:}"

2017-02-04 16:39:06
前へ 1 2 3 ・・ 10 次へ