Extraer una cadena, de acuerdo con un patrón, en un script bash

17

En bash, supongamos que tengo una cadena strname:

strname="ph7go04325r"

Me gustaría extraer los caracteres entre el primer "3" carácter y el último "r" carácter strname, guardando el resultado en una cadena strresult. En el ejemplo anterior, el resultado strresultsería:

strresult="25"

El primer "3"carácter no está necesariamente en la posición de cadena 8 en strname; Del mismo modo, el último no"r" está necesariamente en la posición de la cadena 11. Por lo tanto, las dos cadenas siguientes deberían producir :strnamestrresult="25"

strname="ph11go04325raa"
strname="325r"
strname="rgo04325raa"

Además, strname=ph12go04330raa"debería ceder strresult="30".

Soy nuevo en bash scripting, y no sé por dónde comenzar a hacer una coincidencia de patrones de cadena como esta. ¿Tienes alguna sugerencia?

Andrés
fuente

Respuestas:

28

Puede usar una expresión regular en bash (3.0 o superior) para lograr esto:

if [[ $strname =~ 3(.+)r ]]; then
    strresult=${BASH_REMATCH[1]}
else
    echo "unable to parse string $strname"
fi

En bash, los grupos de captura de una expresión regular se colocan en la matriz especial BASH_REMATCH. El elemento 0 contiene la coincidencia completa, y 1 contiene la coincidencia para el primer grupo de captura.

jordanm
fuente
10

En la shsintaxis estándar (por lo que funcionaría con cualquier versión basho cualquier otro shell compatible con POSIX), usted haría:

case $strname in
  (*3*r*) 
    strresult=${strname#*3}
    strresult=${strresult%r*};;
  (*)
    printf >&2 '%s\n' "Unable to parse string $strname"
esac

Vea también la antigua exprsolución que incluso funcionará en Unices de 35 años:

expr "x$strname" : 'x[^3]*3\(.*\)r'

El viejo capricho con expres que si el partido no se obtiene un código de salida distinto de cero (muy bien), pero también te dan un código de salida distinto de cero si las cadenas devueltas resuelve a 0 (como con strname=zz300rzz).

Stéphane Chazelas
fuente
Creo que tu fraseo incorrectamente implica que esto solo se puede hacer con versiones anteriores de bash. La expansión de parámetros es, por supuesto, todavía un buen enfoque en los depósitos modernos.
kojiro
1
@kojiro, veo a qué te refieres. La formulación inicial fue hacer un seguimiento de la respuesta de Jordan. He actualizado mi respuesta.
Stéphane Chazelas