¿Cómo puedo hacer coincidir una cadena con una regex en Bash?

Estoy tratando de escribir un script bash que contenga una función para que cuando se le dé un archivo .tar, .tar.bz2, .tar.gz etc. utilice tar con los interruptores pertinentes para descomprimir el archivo.

Estoy usando sentencias if elif then que prueban el nombre del archivo para ver con qué termina y no puedo conseguir que coincida usando metacaracteres regex.

Para ahorrarme el tener que reescribir constantemente el script estoy usando 'test' en la línea de comandos, pensé que la sentencia de abajo debería funcionar, he probado todas las combinaciones posibles de paréntesis, comillas y metacaracteres y todavía falla.

test sed-4.2.2.tar.bz2 = tar\.bz2$; echo $?
(this returns 1, false)

Estoy seguro de que el problema es sencillo y he buscado por todas partes, pero no consigo entender cómo hacerlo. ¿Alguien sabe cómo puedo hacerlo?

Solución

Para hacer coincidir las expresiones regulares es necesario utilizar el operador =~.

Pruebe esto:

[[ sed-4.2.2.tar.bz2 =~ tar.bz2$ ]] && echo matched

También puede utilizar comodines (en lugar de expresiones regulares) con el operador ==:

[[ sed-4.2.2.tar.bz2 == *tar.bz2 ]] && echo matched

Si la portabilidad no es una preocupación, recomiendo el uso de [[ en lugar de [ o test ya que es más seguro y más potente. Ver [¿Cuál es la diferencia entre test, [ y? para más detalles.

Comentarios (8)

Una función para hacer esto

extract () {
  if [ -f $1 ] ; then
      case $1 in
          *.tar.bz2)   tar xvjf $1    ;;
          *.tar.gz)    tar xvzf $1    ;;
          *.bz2)       bunzip2 $1     ;;
          *.rar)       rar x $1       ;;
          *.gz)        gunzip $1      ;;
          *.tar)       tar xvf $1     ;;
          *.tbz2)      tar xvjf $1    ;;
          *.tgz)       tar xvzf $1    ;;
          *.zip)       unzip $1       ;;
          *.Z)         uncompress $1  ;;
          *.7z)        7z x $1        ;;
          *)           echo "don't know '$1'..." ;;
      esac
  else
      echo "'$1' is not a valid file!"
  fi
}

Otra Nota

En respuesta a Aquarius Power en el comentario anterior, Necesitamos almacenar la regex en un var

La variable BASH_REMATCH se establece después de que coincida con la expresión, y ${BASH_REMATCH[n]} coincidirá con el enésimo grupo envuelto en paréntesis, es decir, en lo siguiente ${BASH_REMATCH[1]} = "comprimido"y${BASH_REMATCH[2]} = ".gz"`.

if [[ "compressed.gz" =~ ^(.*)(\.[a-z]{1,5})$ ]]; 
then 
  echo ${BASH_REMATCH[2]} ; 
else 
  echo "Not proper format"; 
fi

(La regex anterior no pretende ser válida para la denominación de archivos y extensiones, pero funciona para el ejemplo)

Comentarios (3)

shopt -s nocasematch

if [[ sed-4.2.2.$LINE =~ (yes|y)$ ]]
 then exit 0 
fi
Comentarios (0)