Cadenas en bash

A veces se encuentran ciertas limitaciones a la hora de escribir scripts de shell en el manejo de cadenas y es que, muchas veces, nos olvidamos de que bash tiene un montón de operaciones sobre strings. Por ejemplo:

# Cadena de ejemplo:
string=123.abc.456.ABC.123

# Ver la longitud de la cadena
$ echo ${#string}
19

# Extraer subcadena desde una posicion
$ echo ${string:4}
abc.456.ABC.123

# Extraer subcadena de longitud determinada
# desde una posicion
$ echo ${string:4:7}
abc.456

# Eliminar la cadena coincidente del principio de la cadena
$ echo ${string#123}
.abc.456.ABC.123

# Eliminar la cadena coincidente del final de la cadena
$ echo ${string%123}
123.abc.456.ABC.

# Reemplazar la primera aparación de una subcadena en la cadena
$ echo ${string/123/QWE}
QWE.abc.456.ABC.123

# Reemplazar todas las apariciones de una subcadena en la cadena
$ echo ${string//123/QWE}
QWE.abc.456.ABC.QWE

# Reemplazar si hay coincidencia al pricipio o al final de la cadena:
$ echo ${string/#123/QWE}
QWE.abc.456.ABC.123

$ echo ${string/%123/QWE}
123.abc.456.ABC.QWE

# Longitud de la coincidencia al principio de la cadena (dos formas)
$ expr match "$string" '123'
3
$ expr "$string" : '123'
3

Comparación de cadenas

Otra cuestión donde no es difícil cometer errores es en las comparaciones; al no ser bash un lenguaje tipado, ciertas construcciones pueden dar lugar a errores que pasan desapercibidos y llegan a ser difíciles de detectar. Así que recordemos:

El operador de comparación es =, no -eq.

Ejemplos:

$ $a=foo
$ $b=bar
$ [ "$a" = "$b" ] && echo 'las dos variables son iguales' || echo 'las dos variables son distintas'
las dos variables son distintas

$ [ "$a"="$b" ] && echo 'las dos variables son iguales' || echo 'las dos variables son distintas'
las dos variables son iguales

== es sinónimo de =

$ [ "$a" == "$b" ] && echo 'las dos variables son iguales' || echo 'las dos variables son distintas'
las dos variables son distintas

El operador “distinto de” es !=

$ if [ "$a" != "$b" ]; then echo "Las dos variables son distintas"; fi
Las dos variables son distintas

Pero, con dobles corchetes, el funcionamiento es distinto (pattern matching):

$ filename=foto.jpg
$ if [[ "$filename" != *.gif ]]; then echo "El fichero no parece un gif"; fi
El fichero no parece un gif
Si las expresiones son compuestas, se pueden usar los operadores -a (y lógico) y -o (o lógico). Y, sólo en el caso de usar dobles corchetes, sus “casi” equivalentes && y  
$ if [ "$a" = "foo" -a "$b" = "bar" ]; then echo "foobar"; fi
$ if [[ "$a" == "foo" && "$b" == "bar" ]]; then echo "foobar"; fi