forma compatible con checkbashisms para determinar el shell actual

18

En mi .profile, utilizo el siguiente código para asegurar que las funciones y los alias relacionados con Bash solo se obtienen si el shell de inicio de sesión es realmente Bash :

# If the current (login) shell is Bash, then
if [ "${BASH_VERSION:-}" ]; then
  # source ~/.bashrc if it exists.
  if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
  fi
fi

Actualmente estoy en el proceso de poner mis archivos de configuración de shell, scripts y funciones bajo control de versiones. También he recientemente iniciado el proceso de eliminación del bash casuales de scripts de shell que no se benefician de características Bash-específicas, por ejemplo, la sustitución function funcname()con funcname().

Para los archivos de mi concha repositorio, he configurado un pre-confirmación de gancho que se ejecuta la checkbashismsutilidad de Debian paquete devscripts en cada shfichero en el repositorio para asegurarse de que no introduzcan inadvertidamente sintaxis específica de Bash. Sin embargo, esto genera un error para mi .profile:

possible bashism in .profile line 51 ($BASH_SOMETHING):
if [ "${BASH_VERSION:-}" ]; then

Me preguntaba si había una manera de verificar qué shell se está ejecutando que no activaría una advertencia checkbashisms.

Verifiqué la lista de variables relacionadas con shell enumeradas por POSIX con la esperanza de que una de ellas pudiera usarse para mostrar el shell actual. También he examinado las variables establecidas en un shell de Dash interactivo pero, nuevamente, no he podido encontrar un candidato adecuado.

Por el momento, he excluido .profilede ser procesado por checkbashisms; es un archivo pequeño, por lo que no es difícil verificarlo manualmente. Sin embargo, después de investigar el problema, todavía me gustaría saber si hay un método compatible con POSIX para determinar qué shell se está ejecutando (o al menos una forma que no haga checkbashismsque falle).


Más antecedentes / aclaraciones

Una de las razones por las que pongo mis archivos de configuración de shell bajo control de versiones es para configurar mi entorno en todos los sistemas en los que actualmente me conecto regularmente: Cygwin, Ubuntu y CentOS (ambos 5 y 7, usando Active Directory para el usuario autenticación). Con frecuencia inicio sesión a través de X Windows / entornos de escritorio y SSH para hosts remotos. Sin embargo, me gustaría que esto sea una prueba de futuro y que tenga la menor confianza posible en las dependencias del sistema y otras herramientas.

Lo he estado utilizando checkbashismscomo una comprobación de sanidad simple y automatizada para la sintaxis de mis archivos relacionados con shell. No es una herramienta perfecta, por ejemplo, ya le he aplicado un parche para que no se queje del uso de command -vmis scripts. Mientras investigaba, aprendí que el propósito real del programa es garantizar el cumplimiento de la política de Debian que, según tengo entendido, se basa en POSIX 2004 en lugar de 2008 (o su revisión de 2013).

Anthony G - justicia para Monica
fuente
Lo que está haciendo es tan compatible con POSIX como algo puede ser cuando todo el punto es ejecutar de manera diferente en diferentes entornos compatibles con POSIX. Tu carne es con checkbashisms.
Gilles 'SO- deja de ser malvado'
Y, por cierto, nunca he usado checkbashisms para verificar la portabilidad de mi configuración. Lo reviso usándolo en diferentes sistemas.
Gilles 'SO- deja de ser malvado'
2
Y, por cierto, para lo específico que está haciendo aquí, escriba una .bash_profilefuente de ambos .profiley (condicionalmente) .bashrc.
Gilles 'SO- deja de ser malvado'
Gracias por los comentarios @Gilles. Esa es una solución muy elegante para el problema específico.
Anthony G - justicia para Monica

Respuestas:

16

Tu

# If the current (login) shell is Bash, then
if [ "${BASH_VERSION:-}" ]; then
  # source ~/.bashrc if it exists.
  if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
  fi
fi

el código es completamente compatible con POSIX y la mejor manera de verificar que se esté ejecutando actualmente bash. Por supuesto, la $BASH_VERSIONvariable es específica de bash, ¡pero esa es específicamente la razón por la que la está usando! ¡Para comprobar que estás corriendo bash!

Tenga en cuenta que $BASH_VERSIONse establecerá si bashse invoca como basho sh. Una vez que haya afirmado que está ejecutando bash, puede usar [ -o posix ]como indicador de que se invocó el shell como sh(aunque esa opción también se establece cuando POSIXLY_CORRECT está en el entorno o bashse llama con -o posix, o con SHELLOPTS = posix en el entorno. Pero en todos esos casos, bashse comportará como si se llamara como sh).


Otra variable que podría usar en lugar de $BASH_VERSIONy que checkbashismno parece quejarse a menos que se pase la -xopción $BASH. Eso también es específico, por bashlo que también debería poder usarlo para determinar si está ejecutando basho no.


También diría que no es realmente un uso adecuado de checkbashisms. checkbashismses una herramienta para ayudarlo a escribir shscripts portátiles (según la shespecificación en la política de Debian, un superconjunto de POSIX), ayuda a identificar la sintaxis no estándar introducida por personas que escriben scripts en sistemas donde shhay un enlace simbólico bash.

A .profilees interpretado por diferentes shells, muchos de los cuales no son compatibles con POSIX. En general, no se utiliza shcomo shell de inicio de sesión, pero conchas gusta zsh, fisho bashcon características interactivas más avanzadas.

bashy zsh, cuando no se llama como shy cuando su archivo de sesión de perfil respectivo ( .bash_profile, .zprofile) no es compatible con POSIX (especialmente zsh) pero aún se lee .profile.

Entonces, no es la sintaxis POSIX lo que desea, .profilesino una sintaxis compatible con POSIX (for sh), bashy zshsi alguna vez va a usar esos shells (posiblemente incluso Bourne, ya que el shell Bourne también se lee .profilepero no se encuentra comúnmente en sistemas basados ​​en Linux )

checkbashismsDefinitivamente lo ayudaría a encontrar bashismos, pero puede no señalar la sintaxis POSIX que no es compatible con zsho bash.

Aquí, si desea usar un bashcódigo específico (como la bashsolución de ese error por el cual no se lee ~/.bashrcen shells de inicio de sesión interactivos), un mejor enfoque sería ~/.bash_profilehacerlo (antes o después de buscar ~/.profiledónde pone su sesión común inicializaciones).

Stéphane Chazelas
fuente
Eso no pasa checkbashismsdebido a la variable utilizada.
Thomas Dickey
2
@ThomasDickey, sí, pero ese es un caso en el que se debe ignorar el informe de checkbashisms. Todas las otras soluciones dadas hasta ahora son considerablemente peores.
Stéphane Chazelas
@ StéphaneChazelas Usted dice que todas las demás soluciones son peores. ¿Qué estaría mal usar $0para este caso particular?
Anthony G - justicia para Monica
2
@AnthonyGeoghegan Eso no distingue entre bash llamado as shy algún otro shell llamado as sh.
Gilles 'SO- deja de ser malvado'
También da un falso positivo si dashse llamó incorrectamente a otro shell que no es bash argv[0] == "bash", lo que es totalmente legal, si es poco probable.
Kevin
17

Usualmente se usa $0para este propósito. En el sitio que ha vinculado se encuentra:

0
   (Zero.) Expands to the name of the shell or shell script.
jimmij
fuente
¡Tan sencillo! Me he acostumbrado tanto a usar $0el nombre de un script de shell que me olvidé de que también puede referirse al shell actual. ¡Gracias!
Anthony G - justicia para Monica
1
Como de costumbre, esta convención es respetada por todos los programas que se comportan bien, pero un programa malicioso puede meterse con usted al usar varias llamadas del sistema de la execfamilia porque permiten que el programa que llama identifique el binario que se ejecuta por separado de la cadena para pasarlo como argumento 0.
dmckee
Eso funciona para el .profile :) lindo
Rob
5

Por lo general, la variable de entorno SHELL le indica el shell predeterminado. No debería necesitar obtener manualmente el archivo .bashrc (no es cierto, consulte la actualización a continuación), bash debería hacer esto automáticamente, solo asegúrese de que esté en el directorio $ HOME.

La otra opción es hacer algo como:

 ps -o cmd= $$

eso le dirá el comando (sin argumentos, el = sin un valor no mostrará los encabezados de columna) del proceso actual. Salida de ejemplo:

 $ps -o cmd= $$
 bash
 $sh
 $ps -o cmd= $$
 sh

ACTUALIZAR:

Estoy corregido! :)

El .bashrc no siempre se obtiene como se mencionó en los comentarios a continuación y /programming/415403/whats-the-difference-between-bashrc-bash-profile-and-environment

Para que pueda mover su .bashrc a .bash_profile y ver si eso funciona sin tener que hacer la prueba. Si no, tienes la prueba anterior.

Robar
fuente
1
.bashrcen realidad no proviene de un shell de inicio de sesión pero .profile(si existe) o lo .bash_profileson. SHELLPOSIX no lo especifica y, lamentablemente, tampoco lo es la cmdopción de formato ps.
Anthony G - justicia para Monica
1
Esto es lo que usaría, pero también está sujeto a manipulación maliciosa.
dmckee
Tenga en cuenta que si bien ps -o cmd= $$debería funcionar prácticamente en todas partes, la $SHELLvariable es completamente irrelevante. Ese es el shell predeterminado del usuario y no tiene relación con qué shell se está ejecutando actualmente o qué shell está ejecutando un script de shell.
terdon
2
No, realmente no. muchos shells se leerán ~/.profilecuando se inicien como shells de inicio de sesión. Entonces, por ejemplo, $SHELLpodrías ser cshy corres bash -l. Eso comenzará bash como un shell de inicio de sesión, por lo que se leerá ~/.profile, pero $SHELLaún apuntará csh. Además, .profilepodría provenir explícitamente de otro script. Dado que el OP busca la máxima robustez, se deben considerar todo tipo de casos. En cualquier caso, $SHELLno proporciona ninguna información útil sobre el shell actualmente en ejecución.
terdon
2
FWIW, yo también estoy corregido, por SHELLno haber sido especificado por POSIX: pubs.opengroup.org/onlinepubs/9699919799/basedefs/…
Anthony G - justicia para Monica
4

La pregunta solicita el shell de inicio de sesión del usuario , así como el shell actual de una manera que sea agradable checkbashisms. Si ese es el shell en el que el usuario inició sesión, usaría el de /etc/passwd, por ejemplo,

MY_UID=$(id -u)
MYSHELL=$(awk -F: '$3 == '$MY_UID'{ print $7; }' </etc/passwd )

Por supuesto, los usuarios pueden iniciar un nuevo shell después de iniciar sesión. Por supuesto, si uno es bash y el otro no, las pruebas de las variables de entorno de bash pueden no ayudar.

Algunos pueden querer usar en getentlugar de solo el passwdarchivo (pero eso no estaría en el alcance de la pregunta).

Según el comentario sobre LDAP y la sugerencia de logname, este formulario alternativo podría usarse:

MY_NAME=$(logname)
MYSHELL=$(getent passwd | awk -F: '$1 ~ /^'$MY_NAME'$/ {print $7;}' )

Mientras lo probaba, noté que lognameno le gusta su entrada redirigida (así que dejé la expresión dividida). Un programa de verificación rápida getentdebería funcionar en las plataformas mencionadas (aunque eso debería haberse proporcionado en la pregunta original):

Thomas Dickey
fuente
1
Asumiendo que la base de datos del usuario está en / etc / passwd (no LDAP / NIS / mysql ...) y que solo hay un nombre de usuario por ID de usuario. (sería mejor verificar la primera columna $(logname)).
Stéphane Chazelas
iirc, POSIX no define la utilidad necesaria (o la hubiera usado en mi respuesta). Si usar ido una variable modificable por el usuario es una opción diferente.
Thomas Dickey
1
Tenga en cuenta que dije que $(logname)no $LOGNAME. La identificación de usuario y el shell de inicio de sesión se derivan del nombre de usuario utilizado al iniciar sesión. No puede volver del ID de usuario al shell de inicio de sesión, excepto en sistemas donde solo hay un nombre de usuario por ID de usuario. O IOW, la clave principal en la base de datos del usuario es el nombre de usuario, no el uid.
Stéphane Chazelas
Gracias @ThomasDickey por una respuesta desde una perspectiva diferente. Sin embargo, es un poco más complejo de lo que estaba pensando (más como las respuestas de jimmij y Stéphane ). Una de las razones por las que pongo mis archivos de configuración de shell bajo control de versiones es para configurar mi entorno en todos los sistemas en los que actualmente me conecto regularmente: Cygwin, Ubuntu y CentOS (ambos 5 y 7, usando Active Directory para el usuario autenticación). Por esa razón, prefiero mantener la lógica lo más simple posible.
Anthony G - justicia para Monica