Sep 262007
 

Uso de comillas y otros caracteres especiales

Decíamos hace unos días que el bash era un ‘interprete de comandos’, cuya misión es analizar lo que le tecleamos e interpretarlo para ordenarle al sistema operativo lo que debe hacer. Para interpretarlo las órdenes lo primero que hace es dividirlas en palabras. Cuando bash encuentra un espacio en blanco lo entiende como un separador de palabras. Veremos más adelante que el espacio no es el único separador y que además puede cambiarse el caracter que actúa como separador, pero por ahora nos quedaremos con que el espacio separa palabras y que da lo mismo que pongamos uno o varios.

A veces es necesario que los espacios no actúen como separadores. Supongamos que estuvimos retocando una foto con el gimp y la hemos guardado con el nombre ‘Foto de mi amigo juan.jpg’, el propio nombre del fichero contiene espacios. Ahora queremos ver cuanto ocupa ese fichero en el disco, porque el servidor al que vamos a enviarla no admite ficheros de más de 600Kb. Podríamos usar la orden ‘du’ (disk usage) seguida del nombre del fichero, pero si escribimos:

$ du Foto de mi amigo juan.odt

El bash encuentra los espacios y los entiende como separadores, divide la línea en 6 palabras y toma la primera como un comando y las otras cinco como los argumentos que debe pasarle a ese comando. Evidentemente el comando ‘du’, que espera recibir como argumentos nombres de fichero o de directorio, nos dirá que no encuentra el fichero ‘Foto’, ni el fichero ‘de’, ni tampoco ‘mi’, ni ‘amigo’, ni por supuesto ‘juan.odt’.

En este caso concreto una solución es entrecomillar el nombre del fichero.

$ du 'Carta para mi amigo juan.odt'

Todo lo que bash encuentre entre dos comillas simples lo considerará como una sola palabra. El conflicto podría venir si el nombre fichero fuese “Don’t Cry For Me Argentina by Synead o’Connor.mp3″, y me explico: al interpretar el comando:

$ du 'Don't Cry For Me Argentina by Synead o'Connor.mp3'

Bash empareja primero las comillas simples: La primera se empareja con la que hay entre la D y la t de Don’t, y la que hay en o’Connor se empareja con la última, y por la mitad nos quedan un montón de espacios sin entrecomillar que delimitan las palabras Cry, For, Me…

En casos así podemos usar las comillas dobles. Entre comillas dobles los espacios y otros separadores, y las comillas simples pierden su significado como delimitadores. Y entre comillas simples los espacios, las comillas dobles y todos los caracteres especiales también pierden todo su significado. Más adelante veremos que en realidad las comillas simples son ‘más duras’; ya que hay ciertos caracteres especiales que pierden su significado dentro de ellas pero no dentro de las dobles, pero eso sería anticipar acontecimientos. Por ahora solo quiero que quede claro que ambas nos sirven para lo mismo, para agrupar en un solo argumento palabras que de otro modo estarían separadas. Así que creo que todo funcionará como queremos si escribimos:

$ du "Don't Cry For Me Argentina by Synead o'Connor.mp3"

Otro caso en el que las comillas nos resultarían muy útiles podría ser este:

$ echo Hola        Pepe
Hola Pepe

El comando ‘echo’ escribe en pantalla todos los argumentos que se le pasan, es como un loro que repite lo que le dices (o mejor como el eco). En este caso recibe dos argumentos, y los muestra uno a continuación
del otro. Sin embargo:

$ echo "Hola        Pepe"
Hola        Pepe
$ echo 'Hola        Pepe'
Hola        Pepe

En estos dos casos hay un único argumento, que contiene varios espacios en blanco, y se muestra tal cual.

Ya que las comillas más exteriores siempre que sean de otro tipo anulan el efecto de las interiores, los ejemplos siguientes son todos formas válidas de representar palabras que contienen en si mismas los caracteres de comillas simples o dobles:

$ echo "Este curso se titula 'Curso de bash para fotógrafos linuxeros'"
$ echo 'Este curso se titula "Curso de bash para fotógrafos linuxeros"'
$ echo "Ese programa es de Mc'Affe"
$ echo 'Ponlo entre comillas (")'

Pero no podemos meter una comilla doble entre comillas dobles o una simple entre simples, así sin más, porque se entendería que ha finalizado el bloque entrecomillado. Si fuese necesario poner comillas dobles dentro de un bloque encerrado entre comillas dobles podríamos recurrir al carácter de escape. El carácter de escape es el ‘\’ (no confundir con la tecla escape ¡eh!) y cuando lo ponemos hace que el carácter que va inmediatamente a continuación, si tenía un significado especial, lo pierda y sea tratado como un carácter normal perteneciente a la palabra en la que está contenido.


$ echo o\'Donell
$ echo "Estás leyendo el \"Curso de bash para fotógrafos linuxeros\""

Pero, ojo, dentro de comillas simples el propio caracter de escape pierde su significado y se comporta como un caracter normal, por lo tanto no tiene efecto. Mejor dicho: Entre comillas simples todo lo que pongamos se toma como un caracter normal, nada tiene significado especial. Ni siquiera se puede evitar que otra comilla simple sirva de cierre poniéndole un escape antes. Entre comillas dobles el escape (\) tiene significado especial sólo si va seguido de uno de estos dos símbolos: la propia comilla doble o del propio escape. (Bueno, también del dólar “$” o de la comilla invertida “`”, pero de esos hablaremos a su debido tiempo)

$ echo 'El caracter de escape es \'
El caracter de escape es \

Prueba estos comandos…


$ echo 'Entre comillas simples nada se interpreta "\"'
$ echo "Entre comillas dobles el escape \" \ \' \\ se interpreta a veces \c"
$ echo "Escape \, Comilla doble \", comilla simple '"
$ echo "Escape escapado para que no anule la última comilla \\"
$ echo 'Dentro de comillas simples el escape \\ nunca funciona \'
$ echo Fuera de comillas \c \" \' \ \\ el escape siempre se interpreta.
$ echo "Entre comillas dobles \c \" \' \ \\ sólo si va antes de \" \` \$ ó el propio \\."

No podemos poner

$ echo 'Ese programa es de Mc\'Affe'

porque la comilla de después del escape no perdería su significado, y sería interpretada como el final de la expresión entrecomillada.

El escape lo puedes usar incluso con los espacios u otros separadores, si pones un escape antes de un espacio, éste no funcionará como separador.


$ ls /mnt/windows/Mis\ Documentos

Si pones un escape justo antes de dar al intro, anulas el efecto del intro, y se continúa introduciendo el comando en la siguiente línea, pero al final se tratará como si fuese una sola línea, esto puede ser útil para teclear líneas largas.

$ echo esto \\
  es una \\
  sola línea
esto es una sola línea

Si ponemos un escape antes de un carácter que no tenía ningún significado especial no pasa nada, simplemente se ignora el carácter de escape.

$ echo \Hola
Hola

Si queremos que el propio caracter de escape pierda su significado y sea tratado como un caracter literal, podemos encerrarlo entre comillas simples, como ya vimos, o también lo podemos escapar

$ echo "En DOS los directorios se separan con esta barra \\"
En DOS los directorios se separan con esta barra \

Hasta ahora hemos usado las comillas para encerrar palabras completas, pero no tiene porque ser así, podemos ponerlas solo para encerrar una parte de la palabra, y mientras no haya un separador (espacio) fuera de ellas todo seguirá siendo la misma palabra. Me explico: En estas dos expresiones solo entrecomillamos los espacios, y como las comillas está pegada al resto de la palabra, todo sigue siendo una sola palabra.


$ echo Hola"        "Pepe
Hola        Pepe
$ echo Hola'        'Pepe
Hola        Pepe

Podemos combinar todo esto como queramos. La siguiente orden sólo tiene un argumento, ¿sabrías explicar porqué?:

$ du Don"'"t\ Cry" "For' 'Me' Argentina by Synead 'o\'Connor.mp3