シバンは、スクリプトを実行するシェルを決定しますか?


84

これはばかげた質問かもしれませんが、私はまだ質問します。シバンを宣言した場合

#!/bin/bash 

の初めにmy_shell_script.sh、私は常にbashを使用してこのスクリプトを呼び出す必要がありますか

[my@comp]$bash my_shell_script.sh

または私は例えばを使用できます

[my@comp]$sh my_shell_script.sh

私のスクリプトは、シバンを使用して実行中のシェルを決定しますか?kshシェルでも同じことが起こりますか?AIXを使用しています。


6
少し混乱があります。「_ some_shell some_script」を実行すると、_some_shellが開始され、some_scriptの解釈を要求されます。いいえ、「sh my_shell_script.sh」を実行すると、シバンは解釈されませんが、代わりにshのスクリプトが解釈されます。シバンを使用するには: chmod +x my_shell_script.sh ; /path/to/my_shell_script.sh # or ./my_shell_script.sh if you happen to be in its directory
オリビエデュラック

回答:


117

シェバングは、 #!人間が読み取り可能なインスタンスであるマジックナンバーバイト列からなる0x23 0x21により使用され、exec()実行すべきファイルは、スクリプトまたはバイナリであるかどうかを決定するために関数のファミリー。shebangが存在する場合、exec()代わりにshebangの後に指定された実行可能ファイルを実行します。

これは、質問で示された両方のケースで行われているように、コマンドラインでインタープリターを指定してスクリプトを呼び出すと、コマンドラインでexec()指定されたインタープリターを実行することを意味し、スクリプトも見ないことに注意してください。

したがって、他の人が指摘したようexec()に、shebang行で指定されたインタープリターを呼び出す場合、スクリプトにはとして実行可能ビットが設定され、呼び出される必要があります./my_shell_script.sh

この動作は、次のスクリプトを使用して簡単に実証できます。

#!/bin/ksh
readlink /proc/$$/exe

説明:

  • #!/bin/kshkshインタープリターになるように定義します。

  • $$ 現在のプロセスのPIDを保持します。

  • /proc/pid/exe プロセスの実行可能ファイルへのシンボリックリンクです(少なくともLinuxでは、AIXでは、/ proc / $$ / object / a.outは実行可能ファイルへのリンクです)。

  • readlink シンボリックリンクの値を出力します。

例:

注意:私は、デフォルトのシェルは、Ubuntuの上で、これを実証しています/bin/shためのシンボリックリンクであるダッシュすなわち/bin/dashおよび/bin/kshへのシンボリックリンクで/etc/alternatives/ksh順番にへのシンボリックリンクです、/bin/pdksh

$ chmod +x getshell.sh
$ ./getshell.sh 
/bin/pdksh
$ bash getshell.sh 
/bin/bash
$ sh getshell.sh 
/bin/dash

この答えをありがとうトーマス。Node.jsやJavaなどから子プロセスとしてスクリプトを起動するふりをします。「exec」プロセスを起動してから、execがシェルスクリプトを実行できますか?私はこの質問への答えを探していますbeause私が尋ねる:stackoverflow.com/questions/41067872/...
アレクサンダー・ミルズ

1
@AlexanderMills exec()この回答で言及されているのはシステムコールであり、コマンドexecはシェル組み込みコマンドであるため、Node.jsまたはJavaからexec プログラムを呼び出すことはできません。ただし、Runtime.exec()Java などで呼び出されたシェルコマンドは、最終的にはexec()システムコールによって処理されます。
トーマスナイマン

何とかのNode.jsから低レベルのexec()の呼び出し呼び出すための方法があるかどうえっ、ええ、私はあなたが今述べたのJava APIとindeedeよく知って、私は疑問に思う
アレクサンダー・ミルズ

@AlexanderMills child_process.{exec(),execFile(),spawn()}はすべてCを使用して実装されますexec()(〜を使用process)。
トーマスナイマン

10

はい、そうです。ところで、それはばかげた質問ではありません。私の答えのリファレンスはこちらです。#!でスクリプトを開始する

  • シバンまたは「バング」ラインと呼ばれます。

  • これは、Bashインタープリターへの絶対パスに他なりません。

  • これは、番号記号と感嘆符文字(#!)で構成され、その後に/ bin / bashなどのインタープリターへのフルパスが続きます。

    Linuxでのすべてのスクリプトは、最初の行で指定されたインタープリターを使用して実行されますほとんどすべてのbashスクリプトは、多くの場合、#!/ bin / bashで始まります(Bashが/ binにインストールされていると仮定します)別のシェルで実行される場合。シバンは、ベル研究所でバージョン7 Unixと8の間にデニス・リッチーによって導入されました。その後、BerkeleyのBSDラインにも追加されました。

通訳者ラインを無視する(シバン)

インタープリター行を指定しない場合、デフォルトは通常/ bin / shです。ただし、#!/ bin / bash行を設定することをお勧めします。


3
詳述すると、カーネルは、静的にリンクされたバイナリの実行方法と、他のインタプリタ情報の場所(バイナリの特別なフィールド、またはシェバン行)のみを知っています。通常、シェルスクリプトを実行するということは、シェバン行に従ってシェルに移動し、次にシェルバイナリのDT_INTERPフィールドに従って動的リンカーに移動することを意味します。
サイモンリヒター

5
また、これはシェルスクリプトに限定されないことに注意してください。すべてのテキストベースのスクリプトファイルはこれを使用します。例えば#!/usr/bin/perl #!/usr/local/bin/python #!/usr/local/bin/ruby、複数のシステムをサポートするために使用される他の一般的なシェバングエントリは次のように、あなたが使用したいインタプリタを見つけるためにENVを使用することです#!/usr/bin/env perl #!/usr/bin/env python
sambler

@samblerと言えば、env実際にどちらを好むべきでしょうか?PythonとPerlはをよく使用しますがenv、シェルスクリプトでは、これはしばしば省略され、シェバンは問題のシェルを指します。
ポレモン

1
@polemon少ない方が優先され、より多くのパスが異なります。基本的なシェルは、すべてのシステムで同じパスにあります。perlおよびpythonの最新バージョンは、異なるシステムの異なる場所にインストールできるため、envを使用すると同じシバンが常に機能します。そのため、envはシェルスクリプトよりもperlおよびpythonスクリプトで使用されます。
サンブラー

env$ PATHでプログラムを見つけるのはちょっとしたハックです。名前が示すような環境変数は設定しません。$ PATHは、ユーザーごとに異なる結果になる場合があります。しかし、システム上でスクリプトを変更せずに実行するのに役立ちます。これにより、合理的なperlインタープリターが奇妙な場所に置かれます。
ジョンマハワルド

4

execLinuxカーネルのシステムコールは、シバン(#!)をネイティブに理解します

bashで行う場合:

./something

Linuxでは、これはexecシステムコールをpathで呼び出します./something

カーネルの次の行は、httpsexec//github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25に渡されたファイルで呼び出されます

if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))

ファイルの最初のバイトを読み取り、それらをと比較します#!

比較が真の場合、行の残りはLinuxカーネルによって解析され、最初の引数としてexecパス/usr/bin/env pythonと現在のファイルを使用して別の呼び出しが行われます。

/usr/bin/env python /path/to/script.py

これは#、コメント文字として使用するスクリプト言語で機能します。

はい、次のようにして無限ループを作成できます。

printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a

Bashはエラーを認識します。

-bash: /a: /a: bad interpreter: Too many levels of symbolic links

#! たまたま人間が読める形式ですが、必須ではありません。

ファイルが異なるバイトで開始された場合、execシステムコールは異なるハンドラーを使用します。他の最も重要な組み込みのハンドラは、ELF実行可能ファイルのためのものです:https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305バイトをチェックしている7f 45 4c 46にも人間であることを起こるいます(読み取り可能.ELF)。/bin/lsELF実行可能ファイルであるの最初の4バイトを読み取って確認します。

head -c 4 "$(which ls)" | hd 

出力:

00000000  7f 45 4c 46                                       |.ELF|
00000004                                                                 

そのため、カーネルはこれらのバイトを検出すると、ELFファイルを取得し、それをメモリに正しく配置し、それを使用して新しいプロセスを開始します。参照:https : //stackoverflow.com/questions/8352535/how-does-kernel-get-an-executable-binary-file-running-under-linux/31394861#31394861

最後に、このbinfmt_miscメカニズムを使用して独自のシバンハンドラーを追加できます。たとえば.jarファイルのカスタムハンドラーを追加できます。このメカニズムは、ファイル拡張子によるハンドラーもサポートします。もう1つのアプリケーションは、QEMUを使用して、異なるアーキテクチャの実行可能ファイル透過的に実行することです。

:私は、POSIXしかし、shebangsを指定しないと思うhttps://unix.stackexchange.com/a/346214/32558実行可能なスクリプトは、システムに何かによってサポートされている場合、それは」根拠のセクションでそれを言及し、および形であるが、起こるかもしれない」。


1
./somethingシェルから実行すると、に完全なパスは渡されませんが、exec正確に入力されたパスが渡されます。あなたの答えでこれを修正できますか?やるecho "$0"スクリプトで、あなたは、このような場合は表示されます。
AndiDog

2

実際、結果としてそれを受け取った場合、shebang行に記載されている実行可能ファイルは単なる実行可能ファイルです。一部のテキストインタープリタを実行可能ファイルとして使用することは理にかなっていますが、必ずしも必要ではありません。明確化とデモンストレーションのために、私はかなり役に立たないテストを行いました:

#!/bin/cat
useless text
more useless text
still more useless text

ファイルにtest.txtという名前を付け、実行可能ビットを設定してchmod u+x test.txtから「呼び出し」ました./test.txt。予想どおり、ファイルの内容が出力されます。この場合、catはシェバンラインを無視しません。単にすべての行を出力します。したがって、有用なインタープリターはこのシバン行を無視できるはずです。bash、perl、PHPの場合、これは単なるコメント行です。はい、これらはシェバンラインを無視します。


-1

私が収集したものから、ファイルに実行可能ビットが設定されて呼び出されるたびに、カーネルはファイルヘッダーを分析して処理方法を決定します(私の知る限り、LKMを介してカスタムファイル形式のカスタムハンドラーを追加できます)。ファイルが#!付きのテキストファイルのように見える場合 最初の組み合わせでは、その実行は別の実行可能ファイル(通常は一種のシェル)にディスパッチされます。このパスは、同じ行で、上記のシバンの直後に指定されます。その後、カーネルはシェルを実行し、処理するファイルを渡します。

要するに、どのシェルでスクリプトを呼び出すかは問題ではありません。カーネルはどちらの方法でも実行を適切なシェルにディスパッチします。


4
との間に顕著な違いがbash ./myscript.shあり./myscript.shます。
CVn

この「顕著な違い」とはどういう意味ですか?
jrara

3
@jrara私の答えを見てください。「どのシェルでスクリプトを呼び出すかは関係ありません」というステートメントは、単に真実ではありません。
トーマスナイマン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.