2010-02-27 6 views
58

Me pregunto si la regla general usará la expresión regular en if clause in bash?use la expresión regular en if-condition en bash

Aquí es un ejemplo

$ gg=svm-grid-ch 
$ if [[ $gg == *grid* ]] ; then echo $gg; fi 
svm-grid-ch 
$ if [[ $gg == ^....grid* ]] ; then echo $gg; fi 
$ if [[ $gg == ....grid* ]] ; then echo $gg; fi 
$ if [[ $gg == s...grid* ]] ; then echo $gg; fi 
$ 

Por qué los tres últimos no coincide?

Espero que pueda dar tantas reglas generales como sea posible, no solo para este ejemplo.

Respuesta

91

Cuando se utiliza un patrón global, un signo de interrogación representa un único carácter y un asterisco representa una secuencia de cero o más caracteres:

if [[ $gg == ????grid* ]] ; then echo $gg; fi 

Al usar una expresión regular, un punto representa un solo carácter y un asterisco representa cero o más del personaje anterior. Entonces ".*" representa cero o más de cualquier carácter, "a*" representa cero o más "a", "[0-9]*" representa cero o más dígitos. Otro útil (entre muchos) es el signo más que representa uno o más del carácter anterior. Por lo tanto, "[a-z]+" representa uno o más caracteres alfabéticos en minúsculas (en la configuración regional C, y algunos otros).

if [[ $gg =~ ^....grid.*$ ]] ; then echo $gg; fi 
+0

Entonces, ¿hay dos maneras de hacer coincidir cadenas: patrón global y expresión regular? ¿Glob pettern no solo se usa para nombres de archivos? En bash, ¿cuándo usar el patrón glob y cuándo usar la expresión regular? ¡Gracias! – Tim

+0

@Tim: Globbing está disponible en la mayoría o en todas las versiones de Bash. La coincidencia de Regex solo está disponible en la versión 3 y superior, pero recomendaría solo usarla en 3.2 y versiones posteriores. Los regex son ** mucho ** más versátiles que los globbing. –

12
if [[ $gg =~ ^....grid.* ]] 
+1

Debería poder usar ". {4}" en lugar de "....", es decir, "^. {4} grid. *". Puede ser más fácil de leer y entender. – user276648

3

@OP,

Is glob pettern not only used for file names? 

No "pegote" patrón no sólo se utiliza para nombres de archivo. usted lo usa para comparar cadenas también. En sus ejemplos, puede usar case/esac para buscar patrones de cuerdas.

gg=svm-grid-ch 
# looking for the word "grid" in the string $gg 
case "$gg" in 
    *grid*) echo "found";; 
esac 

# [[ $gg =~ ^....grid* ]] 
case "$gg" in ????grid*) echo "found";; esac 

# [[ $gg =~ s...grid* ]] 
case "$gg" in s???grid*) echo "found";; esac 

In bash, when to use glob pattern and when to use regular expression? Thanks!

expresiones regulares son más versátiles y "conveniente" que "patrones globales", sin embargo, a menos que usted está haciendo tareas complejas que "globbing/englobamiento extendido" no puede proporcionar fácilmente, entonces no hay necesita usar regex Regex no son compatibles con la versión de bash < 3.2 (como dennis mencionó), pero aún puede utilizar globbing extendido (estableciendo extglob). para globbing extendido, vea here y algunos ejemplos simples here.

Actualización para OP: Ejemplo para encontrar los archivos que comienzan con 2 caracteres (los puntos medios 1 char "") seguido de "g" usando expresiones regulares

por ejemplo salida

$ shopt -s dotglob 
$ ls -1 * 
abg 
degree 
..g 

$ for file in *; do [[ $file =~ "..g" ]] && echo $file ; done 
abg 
degree 
..g 

En lo anterior , los archivos coinciden porque sus nombres contienen 2 caracteres seguidos por "g". (es decir, ..g).

El equivalente con globbing será algo como esto: (mira reference de sentido de ? y *)

$ for file in ??g*; do echo $file; done 
abg 
degree 
..g 
+0

Gracias ghostdog74. En Bash con una versión superior a 3.2, ¿se puede usar la expresión regular para reemplazar el patrón global siempre que aparezca? ¿O la expresión regular solo puede usarse en algunas circunstancias especiales? Por ejemplo, encontré que "ls ?? g" está funcionando mientras que "ls ..g" no lo está. – Tim

+0

No hay interrupción para usar Regex si es necesario. Tu decides. Tenga en cuenta que la sintaxis de regex es diferente de la sintaxis globbing de shell. entonces 'ls ..g' no funciona. Le está diciendo al shell que busque un archivo que se llame '..g'. En cuanto a aprender sobre la sintaxis de expresiones regulares, puedes probar 'perldoc perlretut',' perldoc perlrequick', o hacer un 'info sed' en la línea de comando. – ghostdog74

5

La adición de esta solución con grep y sh órdenes internas básicas para los interesados ​​en una solución más portátil (independiente de la versión bash; también trabaja con el viejo y simple sh, en plataformas no Linux, etc.)

# GLOB matching 
gg=svm-grid-ch  
case "$gg" in 
    *grid*) echo $gg ;; 
esac 

# REGEXP  
if echo "$gg" | grep '^....grid*' >/dev/null ; then echo $gg ; fi  
if echo "$gg" | grep '....grid*' >/dev/null ; then echo $gg ; fi  
if echo "$gg" | grep 's...grid*' >/dev/null ; then echo $gg ; fi  

# Extended REGEXP 
if echo "$gg" | egrep '(^....grid*|....grid*|s...grid*)' >/dev/null ; then 
    echo $gg 
fi  

Algunas encarnaciones de grep también admiten la opción -q (silenciosa) como alternativa al redireccionamiento a /dev/null, pero la redirección es de nuevo la más portátil.

+0

olvidó un cierre ")" para egrep – ghostdog74

+3

Use 'grep -q' en lugar de' grep>/dev/null'. – bfontaine

Cuestiones relacionadas