Pergunta

Perguntas :

  • O que o kernel fazer se você ficar um shell-script para a linha shebang?
  • Como é que o know Kernel que intérprete para lançamento?

Explicação :

Recentemente queria escrever um invólucro em torno / usr / bin / env , porque o meu CGI Meio Ambiente não permite-me para definir o PATH variável, exceto a nível mundial (que de naturalmente é uma merda!).

Então eu pensei, "OK. Vamos PREPENDPATH set e set PATH em um invólucro em torno env.". O script resultante (aqui chamado env.1 ) ficou assim:

#!/bin/bash
/usr/bin/env PATH=$PREPENDPATH:$PATH $*

que parece que deve funcionar. Eu verifiquei como ambos reagir, após ajuste 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

olhar absolutamente perfeito ! Por enquanto, tudo bem. Mas veja o que acontece com "Olá mundo!".

# 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!"

Eu acho que eu estou faltando algo muito fundamental sobre UNIX.

Estou bem perdido, mesmo depois de olhar para o código-fonte do original env . Ele define o ambiente e inicia o programa (ou assim parece-me ...).

Foi útil?

Solução

Em primeiro lugar, você deve muito raramente usam $* e você deve quase sempre utilizar "$@" vez. Há uma série de perguntas aqui no SO que explicar os prós e contras do porquê.

Em segundo lugar - o comando env tem dois usos principais. Um deles é para imprimir o ambiente atual; a outra é controlar completamente o ambiente de um comando quando ele é executado. O terceiro uso, que você está demonstrando, é modificar o meio ambiente, mas, francamente, não há necessidade para isso -. As conchas são capazes de lidar com isso para você

Modo 1:

env

Modo 2:

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

Esta versão anula todas as variáveis ??de ambiente herdadas e corre command com precisamente o conjunto de ambiente pelos enwar = opções de valor.

O terceiro modo - que altera o ambiente - é menos importante porque você pode fazer isso muito bem com conchas regulares (civilizados). (. Isso significa "não C shell" - mais uma vez, há outras perguntas sobre SO com as respostas que explicam isso) Por exemplo, você poderia muito bem fazer:

#!/bin/bash
export PATH=${PREPENDPATH:?}:$PATH
exec python "$@"

Esta insiste que $PREPENDPATH está definido como uma string não-vazia no meio ambiente, e, em seguida, anexa-lo para $PATH, e as exportações a nova configuração PATH. Em seguida, usando esse novo caminho, ele executa o programa python com os argumentos relevantes. O exec substitui o shell script com python. Note que este é bastante diferente:

#!/bin/bash
PATH=${PREPENDPATH:?}:$PATH exec python "$@"

Aparentemente, esta é a mesma. No entanto, isso irá executar o python encontrada no caminho pré-existente, ainda que com o novo valor do PATH no ambiente do processo. Assim, no exemplo, você acaba executando Python de /usr/bin e não o de /home/pi/prepend/bin.

Na sua situação, eu provavelmente não iria usar env e iria usar apenas uma variante adequada do script com a exportação explícita.

O comando env é incomum porque não reconhece o duplo traço para opções separadas do resto do comando. Isto é em parte porque ele não leva muitas opções, e em parte porque não é claro se o enwar = opções de valor deve vir antes ou depois do traço duplo.

Na verdade, tenho uma série de scripts para a execução (versões diferentes) um servidor de banco de dados. Esses scripts realmente usar env (e um monte de programas de home-grown) para controlar o ambiente do servidor:

#!/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

Outras dicas

Você deve ler atentamente o artigo da Wikipedia sobre shebang .

Quando o sistema vê o número mágico correspondente ao shebang, ele faz um execve no caminho dado depois que o shebang e dá o próprio script como um argumento.

Seu script falha porque o arquivo que você dá (/usr/bin/env.1) não é um executável , mas começa-se por um shebang ....

Idealmente, você pode resolvê-lo usando ... env em seu roteiro com esta linha como um shebang:

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

não vai funcionar embora no linux como ele trata "/usr/bin/env.1 python" como um caminho (ele faz argumentos não dividir)

Assim, a única maneira que eu vejo é escrever seu env.1 em C

EDIT: parece que ninguém belives me ^^, então eu escrevi um simples e env.1.c sujo:

#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;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top