问题:
解释:
我最近想写一个围绕 / usr / bin / env 的包装器,因为我的CGI环境不允许我设置 PATH 变量,除了全局(其中一个)当然糟透了!)。
所以我想,“好的。让我们设置PREPENDPATH并在env的包装器中设置 PATH 。”生成的脚本(此处称为 env.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 的源代码之后,我也很迷茫。它设置环境并启动程序(或者在我看来......)。
答案 0 :(得分:6)
首先,您应该很少使用$*
,而您几乎应该总是使用"$@"
。这里有一些关于SO的问题,这些问题解释了原因的来龙去脉。
第二 - env
命令有两个主要用途。一是打印当前环境;另一种是在命令运行时完全控制命令的环境。您正在演示的第三个用途是修改环境,但坦率地说没有必要 - 外壳完全能够为您处理。
模式1:
env
模式2:
env -i HOME=$HOME PATH=$PREPENDPATH:$PATH ... command args
此版本取消所有继承的环境变量,并使用ENVVAR = value选项设置的环境运行command
。
第三种模式 - 修改环境 - 并不那么重要,因为你可以用常规(文明)炮弹做到这一点。 (这意味着“不是C shell” - 再次,在SO上还有其他问题,答案可以解释这一点。)例如,你可以做得很好:
#!/bin/bash
export PATH=${PREPENDPATH:?}:$PATH
exec python "$@"
这坚持认为$PREPENDPATH
在环境中设置为非空字符串,然后将其预先设置为$PATH
,并导出新的PATH设置。然后,使用新的PATH,它使用相关参数执行python
程序。 exec
用python
替换shell脚本。请注意,这与以下内容完全不同:
#!/bin/bash
PATH=${PREPENDPATH:?}:$PATH exec python "$@"
表面上看,这是一样的。但是,这将执行在预先存在的PATH上找到的python
,尽管在进程环境中具有PATH的新值。因此,在示例中,您最终将从/usr/bin
执行Python而不是/home/pi/prepend/bin
中的Python。
在您的情况下,我可能不会使用env
,只会使用适当的脚本变体和显式导出。
env
命令不常见,因为它无法识别双破折号以将选项与命令的其余部分分开。这部分是因为它不需要很多选项,部分原因是不清楚ENVVAR =值选项是应该在双击之前还是之后。
我实际上有一系列用于运行(不同版本)数据库服务器的脚本。这些脚本确实使用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
答案 1 :(得分:4)
您应该仔细阅读有关shebang的维基百科文章。
当你的系统看到对应于shebang的幻数时,它会在shebang之后的给定路径上执行execve
并将脚本本身作为参数。
您的脚本失败,因为您提供的文件(/usr/bin/env.1
)不是可执行文件,而是由一个shebang开始....
理想情况下,您可以在脚本上使用... env
解决此问题,并使用此行作为shebang:
#!/usr/bin/env /usr/bin/env.1 python
虽然它在linux上不起作用,因为它将“/usr/bin/env.1 python
”视为路径(它不会拆分参数)
所以我看到的唯一方法是在C
中写下env.1
编辑:似乎没有人相信我^^,所以我写了一个简单而又脏的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;
}