Zunächst sollten Sie sehr selten $*
verwenden und Sie sollten stattdessen fast immer "[email protected]"
verwenden. Hier gibt es eine Reihe von Fragen zur SO, die das Warum erklären.
Zweitens - der env
Befehl hat zwei Hauptverwendungen. Eine besteht darin, die aktuelle Umgebung zu drucken; der andere besteht darin, die Umgebung eines Befehls vollständig zu steuern, wenn er ausgeführt wird. Die dritte Verwendung, die Sie demonstrieren, besteht darin, die Umgebung zu modifizieren, aber ehrlich gesagt gibt es keine Notwendigkeit dafür - die Schalen sind durchaus in der Lage, das für Sie zu handhaben.
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 die ENVVAR = Wert-Optionen.
Der dritte Modus - Ändern der Umgebung - ist weniger wichtig, weil Sie mit regulären (zivilisierten) Shells das tun können. (. Das bedeutet „nicht C-Shell“ - auch hier gibt es noch andere Fragen auf SO mit Antworten, die das erklärt) Zum Beispiel könnte man sehr gut tun:
#!/bin/bash
export PATH=${PREPENDPATH:?}:$PATH
exec python "[email protected]"
Diese besteht darauf, dass $PREPENDPATH
zu einem nicht gesetzt leere Zeichenfolge in der Umgebung, und dann vor $PATH
, und exportiert die neue PATH-Einstellung. Mit diesem neuen PATH führt er dann das Programm python
mit den relevanten Argumenten aus. Die exec
ersetzt das Shell-Skript mit python
. Beachten Sie, dass dies ganz anders ist:
#!/bin/bash
PATH=${PREPENDPATH:?}:$PATH exec python "[email protected]"
Vordergründig ist dies nichts weiter. Dies führt jedoch den python
aus, der auf dem bereits vorhandenen PATH gefunden wurde, allerdings mit dem neuen Wert von PATH in der Prozessumgebung. Im Beispiel würden Sie also Python von /usr/bin
ausführen und nicht den von /home/pi/prepend/bin
.
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 Befehl env
ist ungewöhnlich, weil er den Doppelstrich nicht erkennt, um Optionen vom Rest des Befehls zu trennen. Dies liegt zum Teil daran, dass es nicht viele Optionen erfordert, und zum Teil, weil es nicht klar ist, ob die ENVVAR = Wertoptionen vor oder nach dem Doppelstrich stehen sollten.
Ich habe tatsächlich eine Reihe von Skripten zum Ausführen (verschiedene Versionen) eines Datenbankservers. Diese Skripte verwendet env
wirklich (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 "[email protected]"
case "$*" in
(*v*) track-oninit-v $stdout;;
esac
Dies ist nützlich, Informationen, aber wie die OP sagt, sein/ihr Kern nicht nicht laufen Binärdateien (wie die von Ihnen bereitgestellten Bash-Stubs) als erstes Element einer Shebang-Zeile. Meines wird auch nicht; Insbesondere führt der Kernel das Skript mit der problematischen Shebang-Zeile im gewünschten (nicht binären) Interpreter nicht automatisch aus, und dann versucht meine Shell stattdessen, das Skript auszuführen. (Mein Versteppern ist, dass dies ein altes Shell-Verhalten ist, das viele Shells behalten.) – dubiousjim
Ich verstehe nicht, was Sie sagen? Sind Sie der Meinung, dass es (noch) Shells oder Kernel gibt, die '#!/Bin/bash' oder' #!/Bin/ksh' nicht als erste Zeile eines Skripts behandeln? Ich behaupte nicht oder zeige nicht, dass du '#!/Some/script' als Shebang benutzen kannst. –
Den ersten nicht beanspruchen. In der Frage des OP geht es jedoch um die zweite Frage: Er/sie fragte: "Was macht der Kernel, wenn man ein Shell-Skript in die Shebang-Zeile steckt?" und meldet dann Probleme, die von der Verwendung von env.1 als Shebang-Zeile herrühren, wobei env.1 ein Skript ist. (Zufällig suchte ich nach Diskussionen über die Grenzen der Shebang-Linien, die mich hierher brachten. Und ich fand, dass Ihr Beitrag nützliche Informationen hatte. Danke, dass Sie etwas beigetragen haben. Ich habe nur darauf hingewiesen, dass andere Leser vielleicht später kommen. Das, was Sie diskutieren, hilft nicht dabei, die Einschränkungen zu überwinden, auf die das OP gestoßen ist.) – dubiousjim