2010-07-08 19 views
8

El escenario es que los usuarios se les pide que la fuente de un archivo de script:COMO: Detectar fiesta del shell script

$ source envsetup.sh 

Este archivo script puede utilizar fiesta única característica por lo que tienen detectar la cáscara de ejecución es fiesta o no.

Para otras shells que comparten sintaxis común con bash, por ejemplo, sh, zsh, ksh, me gustaría informar una advertencia.

¿Cuál es la forma más confiable de detectar el shell actual en Linux, Cygwin, OS X?

Lo que sé es $ BASH, pero me pregunto si habrá algún error.

Respuesta

13

Hay un montón de variables de entorno que puede ver, pero muchas de ellas no detectarán si se genera un shell diferente de bash. Considere lo siguiente:

bash$ echo "SHELL: $SHELL, shell: $shell, ARGV[0]: $0, PS1: $PS1, prompt: $prompt" 
SHELL: /bin/bash, shell: , ARGV[0]: -bash, PS1: bash$ , prompt: 

bash$ csh 
[lorien:~] daveshawley% echo "SHELL: $SHELL, shell: $shell, \$0: $0, PS1: $PS1, prompt: $prompt" 
SHELL: /bin/bash, shell: /bin/tcsh, ARGV[0]: csh, PS1: bash$ , prompt: [%m:%c3] %n%# 

[lorien:~] daveshawley% bash -r 
bash$ echo "SHELL: $SHELL, shell: $shell, ARGV[0]: $0, PS1: $PS1, prompt: $prompt" 
SHELL: /bin/bash, shell: , ARGV[0]: sh, PS1: bash$ , prompt: 

bash$ zsh 
% echo "SHELL: $SHELL, shell: $shell, ARGV[0]: $0, PS1: $PS1, prompt: $prompt" 
SHELL: /bin/bash, shell: , ARGV[0]: zsh, PS1: % , prompt: % 

% ksh 
$ echo "SHELL: $SHELL, shell: $shell, ARGV[0]: $0, PS1: $PS1, prompt: $prompt" 
SHELL: /bin/bash, shell: , ARGV[0]: ksh, PS1: bash$ , prompt: 

Hay una serie de variables específicas para las distintas conchas excepto que tienen un hábito de ser heredado por sub-proyectiles, que es donde la cosa entorno realmente rompe. Lo único que casi funciona es ps -o command -p $$. Esto técnicamente le proporciona el nombre de comando con el que se ejecuta el shell. En la mayoría de los casos, esto funcionará ... ya que las aplicaciones se inician con alguna variante de la llamada al sistema exec y permite que el nombre del comando y el ejecutable difieran, también es posible que esto falle. Considere lo siguiente:

bash$ exec -a "-csh" bash 
bash$ echo "$0, $SHELL, $BASH" 
-csh, /bin/bash, /bin/bash 
bash$ ps -o command -p $$ 
COMMAND 
-csh 
bash$ 

Otro truco es usar lsof -p $$ | awk '(NR==2) {print $1}'. Esto es probablemente lo más cercano que pueda obtener si tiene la suerte de tener lsof a mano.

2

La variable de entorno SHELL le indicará qué shell de inicio de sesión se está ejecutando.

También puede usar ps $$ para encontrar el shell actual, que puede usarse si desea saber en qué shell se ejecuta el script (no necesariamente el shell de inicio de sesión). Para reducir gradualmente la salida ps a solo el nombre del shell: ps o command= $$ (no estoy seguro de qué tan seguro es para plataformas múltiples, pero funciona en Mac OS X).

+0

Pruebe esto dentro de bash antes de confiar en '$ SHELL':' csh -c 'echo "$ SHELL"' ' –

+0

Mi impresión de la pregunta es que el script necesita saber el shell de inicio de sesión. Usando bash como shell de inicio de sesión, ejecutar ese comando debería devolver bash, lo cual se espera. – Jeff

+0

No es el shell de inicio de sesión. Si inicia sesión use bash y cambie a csh, $ SHELL permanecerá bash, pero 'source' fallará. –

10

Esto funciona también

[ -z "$BASH_VERSION" ] && return 
+1

También puede hacer esto para zsh, entonces 'if [-n" $ {BASH_VERSION} "]; entonces ... elif [-n "$ {ZSH_VERSION}"]; entonces ... fi' –

+0

tiene el script: '#!/bin/sh \ n echo $ BASH_VERSION' e incluso lo ejecuta con sh o csh desde un shell bash:' $ sh./test.sh' y obtendrá el env var de la versión bash preferida por el usuario ...totalmente engañoso de la secuencia de comandos en ejecución – gcb

1

Lo que impide escribir guión portátil (es decir. Shell-independiente)?

+0

Porque upstream depende mucho de ella. No es lo que puedo controlar ;-) –

+0

¿Así que estás reparando algunos scripts existentes para distribuirlos? –

+0

Por curiosidad, ¿qué características específicas de bash pueden ser usadas por 'envsetup.sh'? Me imagino que contiene solo algunas declaraciones 'export A = B' ... –

0

recomendaría tratar de detectar la presencia de la característica que necesita en lugar de bash vs vs zsh etc. Si la característica está presente, usarlo, si no uso una alternativa. Si no hay una buena manera de detectar la función que no sea usarla y verificar si hay errores, entonces aunque es algo desagradable, no tengo una mejor solución. Lo que importa es que debería funcionar de manera más confiable que tratar de detectar bash. Y dado que otros shells (que todavía están en desarrollo) pueden tener esta característica que anteriormente solo funciona como bash en algún momento en el futuro, realmente trata con lo que importa y le permite evitar tener que mantener una base de datos de las versiones de cada shell. soporte que característica y cuáles no.

2

creo que esto sería la cáscara más práctica y compatibles entre

/proc/self/exe --version 2>/dev/null | grep -q 'GNU bash' && USING_BASH=true || USING_BASH=false 

Explicación:

/proc/self siempre apuntará al proceso de ejecución actual, por ejemplo, ejecutar el siguiente revela el pid de readlink auto (no el shell que ejecutó readlink)

$ bash -c 'echo "The shell pid = $$"; echo -n "readlink (subprocess) pid = "; readlink /proc/self; echo "And again the running shells pid = $$"' 

Resultados en:

The shell pid = 34233 
readlink (subprocess) pid = 34234 
And again the running shells pid = 34233 

Ahora: /proc/self/exe es un enlace simbólico al ejecutable corriendo

Ejemplo:

bash -c 'echo -n "readlink binary = "; readlink /proc/self/exe; echo -n "shell binary = "; readlink /proc/$$/exe' 

resultados en:

readlink binary = /bin/readlink 
shell binary = /bin/bash 

Y aquí es el resultados corriendo en dash y zsh, y ejecutando bash thr un enlace simbólico, e incluso a través de una copia.

[email protected]:~$ cp /bin/bash ./my_bash_copy 
[email protected]:~$ ln -s /bin/bash ./hello_bash 
[email protected]:~$ 

[email protected]:~$ dash -c '/proc/self/exe -c "readlink /proc/$$/exe"; zsh -c "/proc/self/exe --version"; ./hello_bash --version | grep bash; ./my_bash_copy --version | grep bash' 
/bin/dash 
zsh 5.0.7 (x86_64-pc-linux-gnu) 
GNU bash, version 4.3.30(1)-release (x86_64-pc-linux-gnu) 
GNU bash, version 4.3.30(1)-release (x86_64-pc-linux-gnu) 
[email protected]:~$ dash -c '/proc/self/exe -c "readlink /proc/$$/exe"; zsh -c "/proc/self/exe --version"; ./hello_bash --version | grep bash; ./my_bash_copy --version | grep bash' 
4

Aquí es una buena manera:

if test -z "$(type -p)" ; then echo bash ; else echo sh ; fi 

y por supuesto puede reemplazar las instrucciones "eco" con cualquier cosa que desee.

=================

Discusión:

  • La variable $SHELL indica cáscara preferido del usuario ... que le dice que nada sobre el caparazón que se está ejecutando en este momento.

  • La prueba $BASH_VERSION es una buena idea en un 99%, pero podría fallar si algún tipo inteligente pega una variable de ese nombre en el entorno sh. Además, no le dice mucho acerca de que no bash shell se está ejecutando.

  • El método $(type -p) es súper fácil, y funciona incluso si algún tipo inteligente crea un archivo llamado "-p" en su $PATH. Además, se puede utilizar como base para una discriminación de 4 vías, o el 80% de una discriminación de 5 vías, como se explica a continuación.

  • Poner un hash-bang es decir, #! en la parte superior de su script hace no garantía de que será alimentado al intérprete de su elección. Por ejemplo, mi ~/.xinitrc se interpreta por /bin/sh sin importar qué hash-bang (si hay) aparece en la parte superior.

  • La buena práctica es probar alguna característica que existe de manera confiable en ambos idiomas, pero que se comporta de manera diferente. Por el contrario, sería no en general seguro para probar la función que desea y ver si falla.Por ejemplo, si desea utilizar la función incorporada declare y no está presente, podría ejecutar un programa y eso tiene un potencial de desventaja ilimitado.

  • A veces es razonable escribir código compatible, utilizando el conjunto de características del mínimo común denominador ... pero a veces no lo es. La mayoría de esas características adicionales se agregaron por una razón. Dado que estos intérpretes son «casi» Turing-completos, está «casi» garantizado que es posible emular uno con el otro ... posible, pero no razonable.
  • Existen dos niveles de incompatibilidad: sintaxis y semántica. Por ejemplo, la sintaxis if-then-else para csh es tan diferente de bash que la única forma de escribir código compatible sería prescindir por completo de las declaraciones if-then-else. Eso es posible, pero impone un alto costo. Si la sintaxis es incorrecta, la secuencia de comandos no se ejecutará en absoluto. Una vez que superas ese obstáculo, hay muchas maneras en que el código de aspecto razonable produce resultados diferentes, según el dialecto del intérprete que se esté ejecutando.
  • Para un programa grande y complicado, no tiene sentido escribir dos versiones. Escríbelo una vez, en el idioma que elija. Si alguien lo inicia bajo el intérprete equivocado, puede detectarlo y simplemente exec, el intérprete correcto.

  • Un detector de 5 vías se puede encontrar aquí:

    https://www.av8n.com/computer/shell-dialect-detect

    Se puede discriminar:

    • fiesta
    • BSD-CSH
    • tablero
    • ksh93
    • zsh5

    Además, en mi caja Ubuntu Xenial, el registro de entrada de 5 vías también cubre los siguientes:

    • ceniza es un enlace simbólico para lanzarse
    • CSH es un enlace simbólico a/bin/bsd -csh
    • ksh es un enlace simbólico a/bin/ksh93
    • sh es un enlace simbólico para lanzarse