¿Cómo niego una prueba con expresiones regulares en un script bash?

174

Utilizando GNU bash (versión 4.0.35 (1) -release (x86_64-suse-linux-gnu), me gustaría negar una prueba con expresiones regulares. Por ejemplo, me gustaría agregar condicionalmente una ruta a la variable PATH, si el camino aún no está allí, como en:

TEMP=/mnt/silo/bin
if [[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/Scripts:
if [[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/local/bin
if [[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
export PATH

Estoy seguro de que hay un millón de formas de hacer esto, pero lo que me gustaría saber es si el condicional se puede negar de alguna manera, como en (lo erróneo):

TEMP=/mnt/silo/bin
if ![[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/Scripts:
if ![[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/local/bin
if ![[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH:$TEMP; fi
export PATH
David Rogers
fuente

Respuestas:

194

Lo tenías bien, solo pon un espacio entre el !y [[similaresif ! [[

SiegeX
fuente
14
Oye vey! ¡Justo cuando esquivo con seguridad la locura de personaje especial intergaláctico de Perl, me encuentro perdido en el espacio bash (colocación)! (Siento miedo apretando mi intestino como una pitón). ¡Gracias!
David Rogers
126

También puede poner el signo de exclamación dentro de los corchetes:

if [[ ! $PATH =~ $temp ]]

pero debe anclar su patrón para reducir los falsos positivos:

temp=/mnt/silo/bin
pattern="(^|:)${temp}(:|$)"
if [[ ! "${PATH}" =~ ${pattern} ]]

que busca una coincidencia al principio o al final con dos puntos antes o después (o ambos). Recomiendo usar minúsculas o nombres de variables de mayúsculas y minúsculas como hábito para reducir la posibilidad de colisiones de nombres con variables de shell.

Pausado hasta nuevo aviso.
fuente
Ah, gracias por el recordatorio sobre el anclaje. La idea de usar nombres de variables en minúsculas o mixtas es confusa para un principiante de bash, ya que el consejo que he visto hasta ahora es usar mayúsculas. Entiendo lo que está diciendo, pero no he visto suficientes ejemplos de scripts de bash para sentirme cómodo al apartarme (de mi comprensión) del libro de cocina.
David Rogers
44
@anyoneis confía en nosotros en este caso. Se debe evitar el uso de variables en mayúsculas definidas por el usuario. Todas las variables en bash se expanden con $lo que no hay razón para ponerlas en mayúsculas para que se destaquen.
SiegeX
Me parece if [[ ! $foo =~ bar ]]más seguro que if ! [[ $foo =~ bar ]], porque hace que sea más fácil introducir más condiciones en elif
CTodea
19

la forma más segura es poner el! para la negación regex dentro de [[ ]]esto:

if [[ ! ${STR} =~ YOUR_REGEX ]]; then

de lo contrario, podría fallar en ciertos sistemas.

no es asunto tuyo
fuente
9

Sí, puede negar la prueba como SiegeX ya ha señalado.

Sin embargo, no debe usar expresiones regulares para esto; puede fallar si su ruta contiene caracteres especiales. Intenta esto en su lugar:

[[ ":$PATH:" != *":$1:"* ]]

(Fuente)

Mark Byers
fuente
1
Otra razón para usar este formulario es que no coincidirá accidentalmente con las subcadenas (por ejemplo, no puede agregar "/ bin" a la ruta porque "/ usr / bin" ya está allí).
Gordon Davisson
Me tomó un tiempo entender cómo los dos puntos a la izquierda me dieron el anclaje que quería. Vale la pena recordar la idea de reducir el patrón agregando material a la cadena a buscar. No entiendo por qué los caracteres especiales en la ruta interrumpirían la solución regex pero no la solución del patrón bash. ¿Puedes darme un ejemplo?
David Rogers
No creo que esto funcione de manera confiable en todos los casos. Emparejamiento de expresiones regulares en mi humilde opinión superior
Felipe Alvarez
5

Me gusta simplificar el código sin usar operadores condicionales en tales casos:

TEMP=/mnt/silo/bin
[[ ${PATH} =~ ${TEMP} ]] || PATH=$PATH:$TEMP
dimir
fuente