質問

質問:

  • シバン行にシェルスクリプトを挿入すると、カーネルは何をするのでしょうか?
  • カーネルはどのインタープリターを起動するかをどのようにして知るのでしょうか?

説明:

最近ラッパーを書きたいと思っていました /usr/bin/env 私の CGI 環境では設定できないため、 パス グローバルを除いて変数です (もちろんこれは最悪です!)。

そこで私はこう思いました。PREPENDPATHを設定して設定しましょう パス 環境のラッパー内で。」結果として得られるスクリプト (ここでは 環境1) 次のようになりました。

#!/bin/bash
/usr/bin/env PATH=$PREPENDPATH:$PATH $*

それはうまくいくはずです。PREPENDPATH を設定した後、両方がどのように反応するかを確認しました。

$ which /usr/bin/env python
/usr/bin/env
/usr/bin/python

$ which /usr/bin/env.1 python
/usr/bin/env
/home/pi/prepend/bin/python

絶対見てください 完璧!ここまでは順調ですね。しかし、「Hello World!」はどうなるかを見てください。

# Shebang is #!/usr/bin/env python
$ test-env.py
Hello World!

# Shebang is #!/usr/bin/env.1 python
$ test-env.1.py
Warning: unknown mime-type for "Hello World!" -- using "application/*"
Error: no such file "Hello World!"

UNIX に関するかなり基本的なものが欠けているようです。

オリジナルのソースコードを見てもかなり迷ってしまいます 環境. 。環境を設定し、プログラムを起動します (そう私には思えます...)。

役に立ちましたか?

解決

まず第一に、あなたはめったに使うべきではありません$*、あなたはほとんどの代わりに"$@"使用する必要があります。理由のインとアウトを説明するように、ここで質問の数があります。

セカンド - envコマンドは、2つの主要な用途があります。一つは、現在の環境を印刷することです。他のは、それが実行されたときに完全にコマンドの環境を制御することです。あなたが実証されている第三の使用は、環境を変更することですが、率直に言って、そのための必要はありません - 。シェルは、あなたのためにそれを扱うのは非常に能力がある

モード1:

env

モード2:

env -i HOME=$HOME PATH=$PREPENDPATH:$PATH ... command args

このバージョンは、ENVVAR = valueのオプションで設定された正確な環境でcommandすべての継承された環境変数と実行を中止します。

第三モード - 環境を改正は - あなたが定期的に(文明)のシェルとその罰金を行うことができますので、それほど重要ではありません。 (これは「ないCシェル」を意味 - 再び、それを説明するの答えとSO上の他の質問があります。)たとえば、あなたが完全によく行うことができます:

#!/bin/bash
export PATH=${PREPENDPATH:?}:$PATH
exec python "$@"

この環境での非空の文字列に$PREPENDPATH設定されていると主張し、その後$PATHするためにそれを付加し、新しいPATHの設定をエクスポートします。次に、その新しいPATHを使用して、それが関連する引数を指定してpythonプログラムを実行します。 exec /usr/binでシェルスクリプトを置き換えます。これはかなり異なっていることに注意してください:

#!/bin/bash
PATH=${PREPENDPATH:?}:$PATH exec python "$@"

表面的に、これは同じです。しかし、これは/home/pi/prepend/binプロセスの環境でのPATHの新しい値であるものの、既存のPATHに見つかった実行されます。ですから、この例では、あなたが<=>はなく、<=>から1からのPythonを実行してしまうと思います。

あなたの状況では、私はおそらく使用することはありません<=>とだけ明示的な輸出とスクリプトの適切なバリアントを使用することになります。

それは、コマンドの残りの部分からオプションを分離するためにダブルダッシュを認識しないので、

<=>コマンドは珍しいです。それは多くのオプションをとらないので、これは一部であり、部分的にはENVVAR =値オプションは、二重ダッシュの前または後に来る必要があるかどうかは明らかではないからです。

私は実際に(異なるバージョンの)データベース・サーバを実行するための一連のスクリプトを持っています。これらのスクリプトは、実際のサーバーの環境を制御するために<=>使用(と自家製のプログラムの束):

#!/bin/ksh
#
# @(#)$Id: boot.black_19.sh,v 1.3 2008/06/25 15:44:44 jleffler Exp $
#
# Boot server black_19 - IDS 11.50.FC1

IXD=/usr/informix/11.50.FC1
IXS=black_19
cd $IXD || exit 1

IXF=$IXD/do.not.start.$IXS
if [ -f $IXF ]
then
    echo "$0: will not start server $IXS because file $IXF exists" 1>&2
    exit 1
fi

ONINIT=$IXD/bin/oninit.$IXS
if [ ! -f $ONINIT ]
then ONINIT=$IXD/bin/oninit
fi

tmpdir=$IXD/tmp
DAEMONIZE=/work1/jleffler/bin/daemonize
stdout=$tmpdir/$IXS.stdout
stderr=$tmpdir/$IXS.stderr

if [ ! -d $tmpdir ]
then asroot -u informix -g informix -C -- mkdir -p $tmpdir
fi

# Specialized programs carried to extremes:
#   * asroot sets UID and GID values and then executes
#   * env, which sets the environment precisely and then executes
#   * daemonize, which makes the process into a daemon and then executes
#   * oninit, which is what we really wanted to run in the first place!
# NB: daemonize defaults stdin to /dev/null and could set umask but
#     oninit dinks with it all the time so there is no real point.
# NB: daemonize should not be necessary, but oninit doesn't close its
#     controlling terminal and therefore causes cron-jobs that restart
#     it to hang, and interactive shells that started it to hang, and
#     tracing programs.
# ??? Anyone want to integrate truss into this sequence?

asroot -u informix -g informix -C -a dbaao -a dbsso -- \
    env -i HOME=$IXD \
        INFORMIXDIR=$IXD \
        INFORMIXSERVER=$IXS \
        INFORMIXCONCSMCFG=$IXD/etc/concsm.$IXS \
        IFX_LISTEN_TIMEOUT=3 \
        ONCONFIG=onconfig.$IXS \
        PATH=/usr/bin:$IXD/bin \
        SHELL=/usr/bin/ksh \
        TZ=UTC0 \
    $DAEMONIZE -act -d $IXD -o $stdout -e $stderr -- \
    $ONINIT "$@"

case "$*" in
(*v*) track-oninit-v $stdout;;
esac

他のヒント

あなたはシェバングについて Wikipediaの記事を熟読する必要があります。

お使いのシステムは、シェバングに対応したマジックナンバーを見ているときに

、それはシェバング後に指定されたパスにexecveを行い、引数としてスクリプト自体を与えます。

あなたが与えるファイル(/usr/bin/env.1)ではありませんので、

あなたのスクリプトが失敗し、の実行の、しかしシェバングによって自身を開始します....

理想的には、あなたがシェバングとしてこのラインをスクリプトにenv ...使用して、それを解決することができます:

#!/usr/bin/env /usr/bin/env.1 python
それは扱いとして

これは

(それは、引数を分割しません)パスとして「/usr/bin/env.1 python」Linux上ものの動作しません

だから私が見る唯一の方法は、あなたのenv.1 Cでの

を書くことです

EDITは:誰も私を^^ belivesないように思えるので、私が書いたシンプルかつ汚いenv.1.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>


const  char* prependpath = "/your/prepend/path/here:";

int main(int argc, char** argv){
  int args_len = argc + 1;
  char* args[args_len];
  const char* env = "/usr/bin/env";
  int i;

  /* arguments: the same */
  args[0] = env;
  for(i=1; i<argc; i++)
    args[i] = argv[i];
  args[argc] = NULL;

  /* environment */
  char* p = getenv("PATH");
  char* newpath = (char*) malloc(strlen(p)
                 + strlen(prependpath));
  sprintf(newpath, "%s%s", prependpath, p);
  setenv("PATH", newpath, 1);

  execv(env, args);
  return 0;
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top