Trabajo en un entorno relativamente heterogéneo donde puedo ejecutar diferentes versiones de Bash en diferentes nodos HPC, máquinas virtuales o mi estación de trabajo personal. Debido a que puse mis scripts de inicio de sesión en un repositorio de Git, me gustaría usar el mismo (ish) en .bashrc
todos los ámbitos, sin un montón de "si este host, entonces ..." - escribe desorden.
Yo al igual que el comportamiento predeterminado de Bash ≤ 4.1 que se expande cd $SOMEPATH
en cd /the/actual/path
al pulsar la Tabtecla. En Bash 4.2 y superior, necesitaría shopt -s direxpand
volver a habilitar este comportamiento, y eso no estuvo disponible hasta 4.2.29 . Sin embargo, este es solo un ejemplo; Otra shopt
opción , posiblemente relacionada , complete_fullquote
(aunque no sé exactamente qué hace) también puede haber cambiado el comportamiento predeterminado en v4.2.
Sin embargo, direxpand
las versiones anteriores de Bash no lo reconocen, y si lo intento shopt -s direxpand
en mi .bashrc
, eso genera un mensaje de error que se imprime en la consola cada vez que inicio sesión en un nodo con un Bash anterior:
-bash: shopt: direxpand: invalid shell option name
Lo que me gustaría hacer es envolver un condicional shop -s direxpand
para habilitar esa opción en Bash> 4.1 de una manera robusta, sin irritar las versiones anteriores de Bash ( es decir , no solo redirigiendo la salida del error /dev/null
).
fuente
.bashrc
. Todavía quería un registro de cómo usar$BASH_VERSINFO
para interrogar la versión mayor / menor del shell en ejecución, para mi propia edificación, razón por la cual terminé de publicar mi propia respuesta.:)
Respuestas:
Compruebe si
direxpand
está presente en la salida deshopt
y habilítelo si es:fuente
grep -q '^direxpand\b'
en caso de que alguna versión futura o bifurcación de bash tenga una opción que contenga esto como una subcadena y se eliminedirexpand
. Es poco probable en este caso específico, pero no cuesta mucho ser robusto.[ -z "$(shopt -po direxpand 2>&-)" ] || shopt -s direxpand
. ¡No más problemas de expresiones regulares! :-)[ -n "blah" ] && shopt blah
la forma en que lo expresas, estás diciendo "si no se admite direxpand, entonces no hagas esto".set -e
en la parte superior, por lo que tiendo a utilizar la lógica de atajos de esta manera.No veo qué hay de malo en redirigir errores
/dev/null
. Si desea que su código sea robustoset -e
, use el idioma común… || true
:Si desea ejecutar algún código de reserva si la opción no existe, use el estado de retorno de
shopt
:Pero si realmente no le gusta redirigir el error, puede usar el mecanismo de finalización para realizar la introspección. Esto supone que no tiene máquinas anticuadas con bash ≤ 2.03 que no tenían finalización programable.
Este método evita la bifurcación, que es lenta en algunos entornos como Cygwin. Lo mismo ocurre con el sencillo
2>/dev/null
, no creo que se pueda superar eso en el rendimiento.fuente
compgen
propuesta. ¡Eso es material de nivel universitario allí mismo! Evitar la redirección a/dev/null
es solo una preferencia personal. Me gusta pedir permiso en lugar de perdón, si eso tiene sentido.:)
compgen -A shopt -X ...
incluso significaba.compgen
esta manera en Unix y Linux , no sé quién lo propuso por primera vez. (Dejé de usar bash como mi shell principal antes de que tuviera una finalización programable). En la programación, generalmente es una mala idea pedir permiso porque existe el riesgo de que la verificación de permisos no coincida con lo que realmente está haciendo, ya sea debido a una codificación error (donde no está comprobando lo que cree que está comprobando) o porque lo que comprobó cambió antes de usarlo .Cuando sepa con certeza que una
shopt
opción específica está disponible en una versión principal / menor / parche de Bash, puede inspeccionar la$BASH_VERSION
variable o los elementos de la$BASH_VERSINFO[]
matriz para habilitarla condicionalmente.Aquí hay una prueba para Bash 4.2.29 o superior, la versión donde
direxpand
se introdujo por primera vez a la serie 4.2:Editar: Para ser claros, esta es una solución ridículamente sobredimensionada para simplemente ignorar un mensaje de error proveniente de sus scripts de inicio de sesión, pero quería documentarlo de todos modos, para mi propia edificación.
Tenga en cuenta los corchetes , que son obligatorios, y el uso de y , que hacen comparaciones léxicas enteras en lugar de (dependientes de la localidad). Si no se cita, el RHS del operador se trata como patrones "extglob" dentro de Bash / condicionales, como se indica aquí , lo que hace una comparación más estética "comienza con" que una expresión regular, IMO.
${BASH_VERSINFO[index]}
-eq
-gt
==
[[
]]
La
$BASH_VERSINFO
matriz contiene toda la información que vería en la salida debash --version
:Cuando no está claro en la documentación para la
shopt
cual las versiones de Bash se admitieron o cambiaron su comportamiento, el método propuesto por Luciano está bien:... como es la solución propuesta por Gilles de simplemente ignorar el error (
shopt -s direxpand 2>/dev/null
) y quizás verificar$?
si es absolutamente necesario.Referencias: 1 , 2 , 3
Lectura relacionada: Set y Shopt - ¿Por qué dos?
fuente
if [[ $BASH_VERSION > 4.3 ]];
(que coincide4.3.0
,5.0
etc., pero también4.3.0-alpha
. No sé si el hecho posterior importa.)direxpand
embargo, la opción está disponible para Bash 4.2; He verificado esto una con la imagen del estibador en v4.2.53 ejecutandodocker run --rm bash:4.2 bash -c shopt | grep direxpand
(y, por añadidura, que de hecho es no disponible en v4.1.17 ejecutandodocker run --rm bash:4.1 bash -c shopt | grep direxpand
).4.2.0
y me topé con el hecho de que no funcionó allí. El registro de cambios también menciona que se agregóbash-4.3-alpha
. Supongo que sería necesario verificarlo${BASH_VERSINFO[2]}
para ser exacto al respecto, pero no sé qué versión lo agregó ...