Frage

Fragen :

  • Was ist der Kern tun, wenn Sie einen Shell-Skript in die shebang Linie kleben?
  • Wie funktioniert der Kernel wissen, welcher Interpreter zu starten?

Erklärung :

Ich wollte vor kurzem ein Wrapper um schreiben / usr / ist / env , weil meine CGI-Umgebung erlaubt mich nicht, die PATH Variable zu setzen, mit der Ausnahme global (die von natürlich saugt!).

So dachte ich: "OK. Lassen Sie uns gesetzt PREPENDPATH und setzen PATH in einem Wrapper um env.". Das resultierende Skript (hier genannt env.1 ) sah wie folgt aus:

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

, die sieht aus wie es funktionieren soll. Ich habe, wie sie beide reagieren nach dem Abbinden 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

Schauen Sie absolut perfekt ! So weit, ist es gut. Aber schauen Sie, was passiert, zu „Hallo Welt!“.

# 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!"

Ich glaube, ich etwas ziemlich grundlegende über UNIX bin fehlt.

ich ziemlich bin verloren, auch nach dem Quellcode der ursprünglichen Suche env . Er legt die Umwelt und startet das Programm (oder so scheint es mir, ...).

War es hilfreich?

Lösung

Zunächst einmal sollten Sie sehr selten $* verwenden und Sie sollten fast immer "$@" stattdessen verwenden. Es gibt eine Reihe von Fragen hier auf SO, die erklären, die Ins und Outs von warum.

Zweitens - der env Befehl hat zwei Hauptanwendungen. Eine davon ist die aktuelle Umgebung zu drucken; der andere ist vollständig die Umgebung eines Befehls zu steuern, wenn es ausgeführt wird. Die dritte Anwendung, die Sie demonstrieren, ist es, die Umgebung zu ändern, aber ehrlich gesagt gibt es keine Notwendigkeit für die. - die Schalen sind durchaus in der Lage, die für Sie Umgang mit

Mode 1:

env

Mode 2:

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

Diese Version hebt alle geerbten Umgebungsvariablen und läuft command genau die Umgebung festgelegt durch den ENVVAR = Wert-Optionen.

Der dritte Modus - die Umwelt zur Änderung - ist weniger wichtig, weil Sie, dass gut mit regelmäßigen (zivilisierten) Schalen tun können. (Das bedeutet, dass „nicht C-Shell“ - auch hier gibt es andere Fragen mit Antworten auf, so dass das erklären.) Zum Beispiel kann man sehr gut tun:

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

Diese besteht darauf, dass $PREPENDPATH auf eine nicht leere Zeichenfolge in der Umgebung festgelegt ist, und prepends es dann $PATH und exportiert die neue PATH-Einstellung. Dann, dass die neue PATH verwenden, führt er das python Programm mit den entsprechenden Argumenten. Die exec ersetzt den Shell-Skript mit python. Beachten Sie, dass dies ganz anders aus:

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

Vordergründig ist dies das gleiche. Dies wird jedoch die python auf der bereits bestehende PATH, wenn auch mit dem neuen Wert von PATH in der Prozessumgebung gefunden auszuführen. So wird in dem Beispiel, würden Sie Python von /usr/bin und nicht einem von /home/pi/prepend/bin am Ende ausgeführt wird.

In Ihrer Situation, würde ich wahrscheinlich env nicht verwenden und würde nur eine geeignete Variante des Skripts mit dem expliziten Export verwenden.

Der env Befehl ist ungewöhnlich, weil es nicht den Doppel-Bindestrich erkennt Optionen aus dem Rest des Befehls zu trennen. Dies ist zum Teil, weil es nicht viele Optionen, und teilweise nicht nehmen, weil nicht klar ist, ob die ENVVAR = Wert Optionen vor oder nach dem Doppelstrich kommen sollten.

Ich habe tatsächlich eine Reihe von Skripten für den Lauf (verschiedene Versionen) ein Datenbankserver. Diese Skripte wirklich verwendet env (und eine Reihe von home-grown-Programmen), um die Umgebung des Servers zu steuern:

#!/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

Andere Tipps

Sie sollten sorgfältig den Wikipedia-Artikel über sheBANG .

Wenn Sie Ihr System die magische Zahl sieht auf den shebang entspricht, es tut einen execve auf dem angegebenen Pfad nach dem shebang und gibt das Skript selbst als Argument.

Ihr Skript schlägt fehl, da die Datei, die Sie (/usr/bin/env.1) geben nicht eine ausführbare Datei , sondern fängt an, sich durch eine shebang ....

Im Idealfall könnte man löst es mit ... env auf Ihrem Skript mit dieser Linie als shebang:

#!/usr/bin/env /usr/bin/env.1 python

Es wird allerdings nicht auf Linux arbeiten, wie es „/usr/bin/env.1 python“ als Weg behandelt (es nicht geteilte Argumente)

So ist die einzige Art, wie ich sehe, ist Ihre env.1 in C zu schreiben

EDIT: scheint, wie mich niemand belives ^^, also hat mich einen einfachen und schmutzigen env.1.c geschrieben:

#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;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top