私は最近シェル スクリプトに深く関わり始めたのですが、スクリプトをファイルに放り込んでマークしてchmod +x
完了させ、/path/to/script.sh
デフォルトのインタープリターに任せていました。シェルに使用していたのは zsh だったので、それがデフォルトだと思っていました。どうやら、/bin/sh
zsh プロンプトからスクリプトを実行しても、それがデフォルトになっているようです。スクリプトに zsh 固有のものを入れ始めたので、 を実行しない限り失敗するからですzsh /path/to/script.sh
。
要点を述べると、私の質問は次のとおりです。
#!/path/to/shell
先頭にシェバン行 ( ) がない場合、どのシェルがスクリプトを実行しますか? 推測します/bin/sh
が、確認できません。- どのプラットフォームでも実行できるシェル スクリプトを作成する場合の「ベスト プラクティス」とは何でしょうか? (はい、これはある意味オープンエンドです)
zsh の使用を試み、zsh が利用できない場合は bash にフォールバックするスクリプトを書くことは可能ですか? 以下のように 2 つの shebang 行を入れてみましたが、
bad interpreter: /bin/zsh: no such file or directory
zsh のないマシンで試すとエラーが発生します。#!/bin/zsh
#!/bin/bash
答え1
先頭にシェバン行 (#!/path/to/shell) がない場合、どのシェルがスクリプトを実行しますか? /bin/sh だと思いますが、確認できません。
カーネルはそのようなスクリプトの実行を拒否し、ENOEXECを返します。そのため、正確な動作はそのようなスクリプトを実行するプログラムによって異なります。から。
- bash 4.2.39 – 自身を使用する
- busybox-ash 1.20.2 – 自身を使用する
- dash 0.5.7 – /bin/sh を実行する
- fish 1.23.1 – ENOEXEC について文句を言い、間違ったファイルのせいにする
- AT&T ksh 93u+2012.08.01 – 自身を使用
- mksh R40f – /bin/sh を実行します
- pdksh 5.2.14 – /bin/sh を実行します
- sh-heirloom 050706 – 自身を使用する
- tcsh 6.18.01 – /bin/sh を実行します
- zsh 5.0.0 – /bin/sh を実行します
- cmd.exe 5.1.2600 – 変な顔をしています。
でglibc関数を実行するexecv()
か、execve()
単にENOEXECを返します。ただし、execvp()
このエラーコードは非表示になり、/bin/shが自動的に呼び出されます。(これは、実行(3p)。
どのプラットフォームでも実行できるシェル スクリプトを作成する場合の「ベスト プラクティス」とは何でしょうか? (はい、これはある意味オープンエンドです)
POSIX定義の機能だけに固執するかsh
、完全にバッシュ(広く入手可能) を配布する場合は、要件に記載してください。
(考えてみると、Perl や Python の方が、構文が優れているだけでなく、移植性もさらに高くなるでしょう。)
いつもシェバン行を追加します。bash または zsh を使用する場合は、#!/usr/bin/env bash
シェルのパスをハードコーディングする代わりに を使用します。(ただし、POSIX シェルは にあることが保証されているため、その場合は/bin/sh
スキップします。)env
(残念ながら、/bin/sh
常に同じとは限りません。GNU自動設定プログラムは対処しなければならないさまざまな癖。
zshを使用しようとし、zshが利用できない場合はbashにフォールバックするスクリプトを書くことは可能ですか?以下のように2つのシェバン行を入れてみましたが、エラーが発生します。不正なインタープリター: /bin/zsh: そのようなファイルまたはディレクトリはありませんzsh のないマシンで試してみると、うまくいきません。
シェバン行は 1 行しか存在できません。改行文字の後のすべてはカーネルによって読み取られず、シェルによってコメントとして扱われます。
その可能#!/bin/sh
として実行し、どのシェルが利用可能かをチェックし、その結果に応じてexec zsh "$0" "$@"
またはを実行するスクリプトを書くことができます。しかし、bashとzshで使用される構文はさまざまな場所で大きく異なるため、exec bash "$0" "$@"
これを実行することはお勧めしませんあなた自身の正気を保つために。
答え2
1) 現在実行しているシェル。(それがどんなシェルであっても)
2) 同じシェル タイプ (bash/dash/ash/csh/その他お好みのタイプ) を使用し、「サポートされているプラットフォーム」に、使用したいシェルがデフォルトでインストールされていることを確認します。また、システムで一般的に使用できるコマンドを使用するようにしてください。マシン固有のオプションは使用しないでください。
3) には実際には「if-then-else」ロジックはありませんinterpreter directive
。サポートしたいすべてのシステムに存在するシェルを指定する必要があります...つまり、スクリプトがすべてのシェルでかなり汎用的である限り、#!/bin/bash
汎用を指定します。#!/bin/sh