Прежде всего, вы должны очень редко использовать $*
, и вы почти всегда должны использовать "$@"
вместо этого. Здесь есть несколько вопросов по SO, которые объясняют, почему и почему.
Второе - команда env
имеет два основных применения. Одним из них является печать текущей среды; другой - полностью контролировать среду команды при ее запуске. Третье применение, которое вы демонстрируете, - это изменение среды, но, честно говоря, в этом нет необходимости - оболочки вполне способны справиться с этим за вас.
Режим 1:
env
Режим 2:
env -i HOME=$HOME PATH=$PREPENDPATH:$PATH ... command args
Эта версия отменяет все унаследованные переменные среды и запускает command
точно с окружением, установленным параметрами ENVVAR = value.
Третий режим - изменение среды - менее важен, потому что вы можете сделать это нормально с обычными (цивилизованными) оболочками. (Это означает «не оболочка C» - опять же, есть и другие вопросы о SO, ответы на которые объясняют это.) Например, вы вполне могли бы сделать:
#!/bin/bash
export PATH=${PREPENDPATH:?}:$PATH
exec python "$@"
Это настаивает на том, что $PREPENDPATH
задается непустой строкой в среде, а затем добавляется к $PATH
и экспортируется новый параметр PATH. Затем, используя этот новый PATH, он запускает программу python
с соответствующими аргументами. exec
заменяет сценарий оболочки на python
. Обратите внимание, что это сильно отличается от:
#!/bin/bash
PATH=${PREPENDPATH:?}:$PATH exec python "$@"
Внешне это то же самое. Однако при этом будет выполнено python
, найденное в ранее существовавшем PATH, хотя и с новым значением PATH в среде процесса. Итак, в этом примере вы в конечном итоге выполняете Python из /usr/bin
, а не из /home/pi/prepend/bin
.
В вашей ситуации я бы, вероятно, не использовал env
, а просто использовал бы соответствующий вариант сценария с явным экспортом.
Команда env
необычна, поскольку она не распознает двойную черту, чтобы отделить параметры от остальной части команды. Это отчасти потому, что не требуется много опций, а отчасти потому, что неясно, должны ли опции ENVVAR = value приходиться до или после двойной черты.
На самом деле у меня есть серия сценариев для запуска (разных версий) сервера базы данных. Эти сценарии действительно используют env
(и несколько отечественных программ) для управления средой сервера:
#!/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