任意のシェルで実行されるシェルスクリプトの作成(複数のシバン行を使用しますか?)


19

私はシェルスクリプトの詳細を調べ始めたばかりで、常にスクリプトをファイルにスローし、マークを付けてchmod +x完了/path/to/script.shし、デフォルトのインタープリターをそのまま使用できるようにしました。シェルに使用しました。どうやら/bin/sh、zshプロンプトからスクリプトを実行した場合でも、スクリプトにzsh固有のものを入れ始め、実行しないと失敗するため、デフォルトであるようですzsh /path/to/script.sh

ポイントを得るために、ここに私の質問があります:

  1. #!/path/to/shell先頭にシェバン行()がない場合、どのシェルがスクリプトを実行しますか?推測します/bin/shが、確認できません。
  2. 任意のプラットフォームで実行されるシェルスクリプトの記述に関して、「ベストプラクティス」と見なされるものは何ですか?(OK、これは一種の無制限の)
  3. zshを使用しようとし、zshが利用できない場合はbashにフォールバックするスクリプトを書くことは可能ですか?以下のように2つのシバン行を入れてbad interpreter: /bin/zsh: no such file or directoryみましたが、zshのないマシンで試してみるとエラーが出ます。

    #!/bin/zsh

    #!/bin/bash

回答:


26

最初にシェバン行(#!/ path / to / shell)がない場合、どのシェルがスクリプトを実行しますか?/ bin / shと仮定していますが、確認できません。

正確な動作は、このようなスクリプトを実行するプログラムに依存しますので、カーネルは、そのようなスクリプトや戻りENOEXECを実行することを拒否から

  • bash 4.2.39 –自身を使用します
  • busybox-ash 1.20.2 –自身を使用
  • ダッシュ0.5.7 – / bin / shを実行
  • 魚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を自動的に呼び出します。(これはexec(3p)で文書化されています。)

任意のプラットフォームで実行されるシェルスクリプトの記述に関して、「ベストプラクティス」と見なされるものは何ですか?(OK、これは一種の無制限の)

shPOSIXで定義された機能のみに固執するか、フルbash(広く利用可能)に移行し、それを配布する場合は要件に記載してください。

(今、私が考えると、Perl(またはおそらくPython)は、より優れた構文を持つことは言うまでもなく、さらに移植性が高くなります。)

常にシェバンラインを追加します。bashまたはzshを使用する場合#!/usr/bin/env bash、シェルのパスをハードコーディングする代わりに使用します。(ただし、POSIXシェルはであることが保証されている/bin/shためenv、その場合はスキップします。)

(残念ながら、/bin/sh常に同じとは限りません。GNUautoconfプログラムは、多くの異なる癖に対処する必要があります。)

zshを使用しようとし、zshが利用できない場合はbashにフォールバックするスクリプトを書くことは可能ですか?以下のように2つのシバン行を入れてみましたが、インタープリターが正しくないだけでエラーになります:/ bin / zsh:zshのないマシンで試してみると、そのようなファイルやディレクトリはありません

シバンラインは1つだけです。改行文字以降はすべてカーネルによって読み取られず、シェルではコメントとして扱われます。

それはだ可能として実行することをスクリプトを記述するために#!/bin/shシェルが利用可能であるチェック、および実行exec zsh "$0" "$@"またはexec bash "$0" "$@"結果に応じて。ただし、bashとzshで使用される構文はさまざまな場所で非常に異なるため、自分の正気のためにこれ行うことはお勧めしません


1
ENOEXECを受け取ったときに各シェルが実際に呼び出していたものをどのようにトレースしましたか?
swrobel

2
@SWrobel:を使用しstrace -f -e fork,clone,execveます。一部のシェルは、/bin/sh失敗後にexec を実行しました。他の人はスクリプト自体を解釈しました。
悲しみ

1
@SWrobel:別の方法は、で構成されるスクリプトを実行することですreadlink /proc/$$/exe
悲しみ


1
以下の場合cshtcsh、動作はスクリプトで始まるかどうかに依存して#(彼らはスクリプトを解釈するために代わりのSH自分自身を呼び出した場合)。それはcshがコメントをサポートしてBourneシェルをサポートしていなかった時代にさかのぼるので、#それはcshスクリプトであるというヒントでした。
SCH

2

1)実行中の現在のシェル(どのようなシェルであっても)

2)同じシェルタイプ(bash / dash / ash / csh /お好みのもの)に固執し、デフォルトで使用するシェルが「サポート対象プラットフォーム」にインストールされていることを確認します。また、システムで一般的に使用可能なコマンドを使用してみてください。マシン固有のオプションは避けてください。

3)に「if-then-else」ロジックは実際にはありませんinterpreter directive。サポートするすべてのシステムに存在するシェルを指定する必要があります。つまり、スクリプトがすべてのシェルでかなり汎用的である限り#!/bin/bash、汎用#!/bin/shを指定する必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.