linux – /usr/bin/env关于shebang line pecularities的问题

问题:

>如果你将shell脚本粘贴到shebang行,内核会做什么?
>内核如何知道要启动哪个解释器?

说明:

我最近想在/usr/bin/env周围编写一个包装器,因为我的CGI环境不允许我设置PATH变量,除了全局(当然这很糟糕!).

所以我想,“好的.让我们设置PREPENDPATH并在环绕包装器中设置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的基本内容.

即使在查看原始环境的源代码后,我也很迷茫.它设置环境并启动程序(或者在我看来……).

解决方法

首先,你应该很少使用$*而你应该总是使用“$@”代替.这里有很多关于SO的问题,这些问题解释了原因的来龙去脉.

第二 – env命令有两个主要用途.一是打印当前环境;另一种是在命令运行时完全控制命令的环境.您正在演示的第三个用途是修改环境,但坦率地说没有必要 – 外壳完全能够为您处理.

模式1:

env

模式2:

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

此版本取消所有继承的环境变量,并使用ENVVAR = value选项设置的环境运行命令.

第三种模式 – 修改环境 – 不太重要,因为你可以用常规(文明)炮弹做到这一点. (这意味着“不是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

相关文章

linux常用进程通信方式包括管道(pipe)、有名管道(FIFO)、...
Linux性能观测工具按类别可分为系统级别和进程级别,系统级别...
本文详细介绍了curl命令基础和高级用法,包括跳过https的证书...
本文包含作者工作中常用到的一些命令,用于诊断网络、磁盘占满...
linux的平均负载表示运行态和就绪态及不可中断状态(正在io)的...
CPU上下文频繁切换会导致系统性能下降,切换分为进程切换、线...