Pregunta

Preguntas:

  • ¿Qué hace el kernel de hacer si usted se pega un shell-script en el shebang línea?
  • ¿Cómo funciona el Kernel de saber que el intérprete para el lanzamiento?

Explicación:

Recientemente he querido escribir una envoltura alrededor de /usr/bin/env porque mi Entorno CGI no me permite establecer el CAMINO variable, excepto a nivel mundial (que por supuesto es una mierda!).

Así que pensé, "OK.Vamos a establecer PREPENDPATH y establecer CAMINO en un contenedor de env.".La secuencia de comandos resultante (aquí llamado env.1) se veía así:

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

que parece que debería funcionar.He comprobado cómo se reacciona, después de establecer 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

Parecen absolutamente perfecto!Tan lejos, tan bueno.Pero veamos lo que ocurre en "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!"

Supongo que me estoy perdiendo algo muy fundamental sobre UNIX.

Estoy bastante perdido, incluso después de mirar el código fuente de la original env.Se establece el entorno y lanza el programa (o eso me parece...).

¿Fue útil?

Solución

Primero de todos, usted debe muy rara vez uso $* y casi siempre uso "$@" en su lugar.Hay una serie de preguntas sobre el MODO en el que se explican los pormenores de por qué.

Segundo - la env comando tiene dos usos principales.Uno es para imprimir el entorno actual;la otra es controlar completamente el entorno de un comando cuando se ejecuta.El tercer uso, que están demostrando, es modificar el medio ambiente, pero, francamente, no hay necesidad de que - las conchas son muy capaces de manejar para usted.

Modo 1:

env

Modo 2:

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

Esta versión cancela todos los heredados de las variables de entorno y se ejecuta command precisamente con el medio ambiente establecido por la ENVVAR=valor de las opciones.

El tercer modo - que modifica el medio ambiente - es menos importante porque puede hacerlo bien con regular (civilizado) las conchas.(Que significa "no shell C" - de nuevo, hay otras preguntas PARA las respuestas que explicar eso.) Por ejemplo, usted podría perfectamente hacer:

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

Este insiste en que $PREPENDPATH se establece una cadena no vacía en el medio ambiente, y, a continuación, se antepone a $PATH, y las exportaciones de la nueva configuración de la RUTA.Luego, utilizando la nueva RUTA de acceso, se ejecuta el python programa con los argumentos relevantes.El exec sustituye a la secuencia de comandos de shell con python.Tenga en cuenta que esto es muy diferente de:

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

Superficialmente, esta es la misma.Sin embargo, se ejecutará el python se encuentran en la pre-RUTA existente, aunque con el nuevo valor de la RUTA de acceso en el proceso del medio ambiente.Así, en el ejemplo, se acabaría la ejecución de Python desde /usr/bin y no el de /home/pi/prepend/bin.

En su situación, probablemente no lo haría uso env y podría usar una variante adecuada de la secuencia de comandos con la explícita a la exportación.

El env comando es inusual porque no reconoce la doble guion para separar las opciones en el resto de la orden.Esto es en parte porque no tiene muchas opciones, y en parte porque no está claro si el ENVVAR=valor de las opciones debe venir antes o después de la doble guión.

La verdad es que tengo una serie de scripts para la ejecución de (diferentes versiones) de un servidor de base de datos.Estas secuencias de comandos a usar realmente env (y un montón de inicio-programas desarrollados) para controlar el entorno del 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

Otros consejos

Debe leer detenidamente el artículo de Wikipedia sobre shebang .

Cuando su sistema ve el número mágico correspondiente al shebang, hace un execve en la ruta dada después del shebang y le da al script en sí mismo un argumento.

Tu script falla porque el archivo que le das (/usr/bin/env.1) no es un ejecutable , sino que comienza con un shebang ...

Idealmente, podría resolverlo usando ... env en su secuencia de comandos con esta línea como un shebang:

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

Sin embargo, no funcionará en Linux, ya que trata " /usr/bin/env.1 python " como una ruta (no divide argumentos)

Entonces, la única forma en que veo es escribir su env.1 en C

EDITAR: parece que nadie me cree ^^, así que he escrito un simple y sucio 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;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top