Linux で `#!/usr/bin/env コマンド --argument` を使用する Shebang ラインが失敗します。

Linux で `#!/usr/bin/env コマンド --argument` を使用する Shebang ラインが失敗します。

簡単なスクリプトがあります。

#!/usr/bin/env ruby --verbose
# script.rb
puts "hi"

私のOSXコンピュータではうまくいきます。

osx% ./script.rb
hi

しかし、私のLinuxコンピュータではエラーが発生します。

linux% ./script.rb
/usr/bin/env: ruby --verbose: No such file or directory

Shebangラインを手動で実行すると正常に動作します。

linux% /usr/bin/env ruby --verbose ./script.rb
hi

ruby --verboseただし、これを単一のパラメータに圧縮すると、エラーを複製できます。env

linux% /usr/bin/env "ruby --verbose" ./script.rb
/usr/bin/env: ruby --verbose: No such file or directory

envしたがって、Shebang Line Resetの問題をこのように説明しているようです。私はGNU coreutils 8.4を使用していますenv

linux% /usr/bin/env --version
env (GNU coreutils) 8.4
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Richard Mlynarik and David MacKenzie.

本当に変に見えますね。これがこのバージョンの一般的な問題ですかenv、それとも私が認識していない他の問題はありますか?

答え1

これは、Linux(BSDとは異なり)がshebangコマンド(この場合はenv)に単一の引数だけを渡すためです。

これはStackOverflowで広く議論されています。

答え2

Coreutils>=8.30:

#!/usr/bin/env -S ruby --verbose

-Sまたは、envオプションは--split-stringGNU coreutilsのマニュアルに記載されています(参照:info '(coreutils) env invocation'またはオンラインマニュアル)。以下は抜粋です:

ほとんどのオペレーティングシステム(例:GNU / Linux、BSD)は、最初のスペースの後のすべてのテキストを単一の引数として扱います。したがって、スクリプトでenvを使用するときに複数のパラメータを指定することはできません。

次の例では:

#!/usr/bin/env perl -T -w print "hello\n";

オペレーティングシステムはこれをperl -T -wパラメータ(プログラム名)として扱い、次のようにスクリプトの実行が失敗します。

/usr/bin/env: 'perl -T -w': No such file or directory

この-Sオプションは、env単一の文字列を複数の引数に分割するように指示します。次の例は期待どおりに機能します。

$ cat hello.pl
#!/usr/bin/env -S perl -T -w print "hello\n";

$ chmod a+x hello.pl $ ./hello.pl hello

perl -T -w hello.plコマンドラインプロンプトで実行するのと同じです。

答え3

@rampionコメントでこれを見つけました。

何が起こるかは、カーネルが#!を探すファイルの最初の2文字を処理することです。これらの文字が見つかったら、すべての空白文字をスキップし、空白以外の文字を探し、他のスクリプトではなく実際の実行可能ファイルでなければならないインタプリタパスを抽出します。ただし、Linuxは再帰スクリプトの処理を可能にするように拡張します。見つかったら、空白ではなく最初の文字にジャンプし、そこから次の改行文字にジャンプして単一の引数としてコマンドに渡します。引用符やその他のメタ文字の「シェリング」はありません。それはすべて非常にシンプルで暴力的です。だからあなたはそこのオプションに興味を持つことはできません。空白を含む引数を取得し、「perl -w」はカーネルがここで見て渡すことです。

源泉:http://lists.gnu.org/archive/html/bug-sh-utils/2002-04/msg00020.html

関連情報