2008-12-09 5 views
6

особенностях Вопросы:/USR/бен/ENV вопросы относительно притон линии

  • Что делает ядро, если вы будете придерживаться шелл-скрипт в хижину линии?
  • Как ядро ​​знает, какой интерпретатор запускается?

Объяснение:

Я недавно хотел написать обертку вокруг /USR/BIN/окр, потому что мой CGI среда не позволяет мне установить переменную в PATH, за исключением того, во всем мире (который конечно, сосет!).

Итак, я подумал: «Хорошо. Давайте установим PREPENDPATH и установите PATH в обертке вокруг env.". Полученный скрипт (здесь называется 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. Он устанавливает среду и запускает программу (или так мне кажется ...).

ответ

6

Прежде всего, вы должны очень редко использовать $*, и вы должны почти всегда использовать "[email protected]". На SO есть ряд вопросов, которые объясняют причины и причины.

Вторая команда env имеет два основных вида использования. Один - напечатать текущую среду; другой - полностью контролировать среду команды при ее запуске. Третье использование, которое вы демонстрируете, - это изменить среду, но, откровенно говоря, в этом нет необходимости - оболочки вполне способны справиться с этим для вас.

Режим 1:

env 

Режим 2:

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

Эта версия отменяет все унаследованные переменные окружения и запускает command именно с окружающей средой, установленной опции ENVVAR = значение.

Третий режим - изменение окружающей среды - менее важен, поскольку вы можете делать это нормально с помощью обычных (цивилизованных) оболочек. (. Это означает, что «не C оболочки» - опять же, есть и другие вопросы по SO с ответами, которые объясняют, что) Например, вы могли бы прекрасно сделать:

#!/bin/bash 
export PATH=${PREPENDPATH:?}:$PATH 
exec python "[email protected]" 

Это настаивает на том, что $PREPENDPATH настроен на не- пустую строку в среде, а затем добавляет ее в $PATH и экспортирует новую настройку PATH. Затем, используя этот новый PATH, он выполняет программу python с соответствующими аргументами. exec заменяет скрипт оболочки python. Обратите внимание, что это совсем не так:

#!/bin/bash 
PATH=${PREPENDPATH:?}:$PATH exec python "[email protected]" 

Поверхностно, это то же самое. Однако это приведет к выполнению 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 "[email protected]" 

case "$*" in 
(*v*) track-oninit-v $stdout;; 
esac 
+0

Это полезная информация, но, как говорит О. П., его/ее ядро ​​не будет работать не- бинарные файлы (например, бас-заглушки, которые вы предоставляете) в качестве первого элемента линии shebang. Мой тоже не будет; в частности, ядро ​​не запускает скрипт с проблематичной линией shebang в желаемом (не двоичном) интерпретаторе, а затем моя оболочка будет пытаться запустить скрипт. (Мое недопонимание заключается в том, что это старое поведение оболочки, которое сохраняет множество оболочек.) – dubiousjim 2012-04-23 17:41:35

4

Вы должны внимательно прочитать статью в Википедии о shebang.

Когда ваша система увидит магическое число, соответствующее shebang, оно делает execve по данному пути после shebang и дает сценарий сам по себе в качестве аргумента.

Ваш скрипт не потому, что файл вы даете (/usr/bin/env.1) не исполняемым, но начинает сам по притон ....

В идеале, вы могли бы решить ее с помощью ...env на вашем сценарии с этой линией, как притон:

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

Это не будет работать, хотя на Linux, как он относится к «/usr/bin/env.1 python» как путь (он не расщепляется аргументы)

Таким образом, единственный Я вижу, чтобы написать env.1 в C

EDIT: кажется, что никто не belives меня ^^, так что я написал простой и грязный 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; 
}