2009-08-07 13 views
14

Tengo un archivo de texto con varias entradas. Cada entrada termina con una línea que contiene todos los asteriscos.¿Cómo puedo asignar la coincidencia de mi expresión regular a una variable?

Me gustaría utilizar comandos de shell para analizar este archivo y asignar cada entrada a una variable. ¿Cómo puedo hacer esto?

Aquí hay un ejemplo de archivo de entrada:

 
*********** 
Field1 
*********** 
Lorem ipsum 
Data to match 
*********** 
More data 
Still more data 
*********** 

Esto es lo que mi solución parece hasta el momento:

#!/bin/bash 
for error in `python example.py | sed -n '/.*/,/^\**$/p'` 
do 
    echo -e $error 
    echo -e "\n" 
done 

Sin embargo, esto sólo asigna a cada palabra en el texto que coincide con $ error, en vez que un bloque completo.

Respuesta

23

Estoy sorprendido de no ver una solución de bash nativa aquí. Sí, bash tiene expresiones regulares. Puede encontrar una gran cantidad de documentación aleatoria en línea, especialmente si incluye "bash_rematch" en su consulta, o simplemente mira las páginas man. Aquí hay un ejemplo tonto, tomado de here y ligeramente modificado, que imprime la coincidencia completa, y cada una de las coincidencias capturadas, para una expresión regular.

if [[ $str =~ $regex ]]; then 
    echo "$str matches" 
    echo "matching substring: ${BASH_REMATCH[0]}" 
    i=1 
    n=${#BASH_REMATCH[*]} 
    while [[ $i -lt $n ]] 
    do 
     echo " capture[$i]: ${BASH_REMATCH[$i]}" 
     let i++ 
    done 
else 
    echo "$str does not match" 
fi 

La cosa importante es que la prueba extendida [[ ... ]] utilizando su expresión regular comparación =~ tiendas de todo el partido en ${BASH_REMATCH[0]} y los partidos capturados en ${BASH_REMATCH[i]}.

+1

De hecho, sería bueno si hubiera una guía definitiva para bash expresiones regulares, pero como dijo @Jefromi, es solo un montón de aleatoriedad. – g33kz0r

+0

@Noah: desde la página del manual: "la cadena a la derecha del operador se considera una expresión regular extendida y se corresponde en consecuencia (como en regex (3)." Entonces, ¿es POSIX extended regex, sí? Eso parece ... bastante definitivo – Cascabel

+0

Eso está muy bien, Jefromi. Pero no es diveintobashregex.org – g33kz0r

0

dependiendo de lo que quiere hacer con las variables

awk ' 
f && /\*/{print "variable:"s;f=0} 
/\*/{ f=1 ;s="";next} 
f{ 
    s=s" "$0 
}' file 

de salida:

# ./test.sh 
variable: Field1 
variable: Lorem ipsum Data to match 
variable: More data Still more data 

lo anterior sólo les imprime. si lo desea, almacene en la matriz para su uso posterior ... ej. matriz [++ d] = s

1

Si desea hacerlo en Bash, podría hacer algo como lo siguiente. Se utiliza esta expansión en lugar de las expresiones regulares (La opción shell extglob permite la coincidencia de patrones extendida, de manera que podemos hacer coincidir una línea que consiste solamente de asteriscos.)

#!/bin/bash 
shopt -s extglob 
entry="" 
while read line 
do 
    case $line in 
     +(\*)) 
      # do something with $entry here 
      entry="" 
      ;; 
     *) 
      entry="$entry$line 
" 
      ;; 
    esac 
done 
0

registros Dividir en (ba) sh no es tan fácil, pero puede se puede hacer usando IFS para dividir en caracteres individuales (simplemente configure IFS = '*' antes de su ciclo for, pero esto genera múltiples registros vacíos y es problemático si cualquier registro contiene un '*'). La solución obvia es usar perl o awk y usar RS para dividir sus registros, ya que esas herramientas proporcionan mejores mecanismos para dividir registros. Una solución híbrida es usar perl para hacer la división de registros y hacer que perl llame a su función bash con el registro que desee. Por ejemplo:

#!/bin/bash 

foo() { 
    echo record start: 
    echo "[email protected]" 
    echo record end 
} 
export -f foo 

perl -e "$/='********'; while(<>){chomp;system(\"foo '\$_'\")}" << 'EOF' 
this is a 2-line 
record 
******** 
the 2nd record 
is 3 lines 
long 
******** 
a 3rd * record 
EOF 

Esto da el siguiente resultado:

 
record start: 
this is a 2-line 
record 

record end 
record start: 

the 2nd record 
is 3 lines 
long 

record end 
record start: 

a 3rd * record 

record end 
+0

Tenga en cuenta que la secuencia de comandos dada aquí casi con seguridad requiere que/bin/sh sea bash. –

1

trate de poner entre comillas el comando.

#!/bin/bash 
for error in "`python example.py | sed -n '/.*/,/^\**$/p'`" 
do 
    echo -e $error 
    echo -e "\n" 
done 
Cuestiones relacionadas