Saltar la navegación

Trabajar con multilíneas

Lo habitual en sed es que en la zona de trabajo solo haya una línea en cada ciclo, y que en la zona auxiliar guardemos una sola línea, pero no tiene que ser siempre así, disponemos de comandos que nos van a permitir trabajar con múltiples líneas separadas con \n.

Cuando en la zona de trabajo hay varías líneas, en las expresiones regulares se usan dos metacaracteres que no suelen usarse cuando solo tenemos una línea, pues están los caracteres especiales ^ y $ que significan lo mismo, pero en modo multilínea estos cambian de significado.

  • \` : Este metacarácter hace referencia al inicio de la zona de trabajo y es una extensión de sed. Como el carácter ` tiene significado especial para el shell, se utiliza para la expansión de comandos por compatibilidad con el Bourne Shell, hay que tener cuidado con la forma de escribirlo. Si va dentro de un script limitado por apóstrofes ('), no hay problemas: ' ... \` ... '. Si el script está limitado por dobles comillas (") es cuando el shell intentaría interpretarlo y para que no lo haga debemos protegerlo: " ... \\\` ... ". En un contexto unilínea significa lo mismo que ^.
  • \' : Este metacarácter hace referencia al final de la zona de trabajo y es una extensión de sed. Debemos usarlo dentro de un script limitado por dobles comillas (") y no por apóstrofes ('). En un contexto unilínea significa lo mismo que $.
  • ^ : Este metacarácter cambia de significado, en modo multilínea representa el inicio de una línea, y hay varios. Si no se activa el modo multilínea representa el inicio de la primera línea o inicio de la zona de trabajo.
  • $ : Este metacarácter cambia de significado, en modo multilínea representa el final de una línea, y hay varios. Si no se activa el modo multilínea representa el final de la última línea o final de la zona de trabajo.

Modificador e (execute, extensión GNU) del comando s

El modificador e trata el contenido de la zona de trabajo como si fuera un comando del shell, de forma que si se produce la sustitución, ejecutará el comando y el resultado de este sustituirá el contenido de la zona de trabajo, que normalmente será multilínea.

$ file f g
f: ASCII text
g: ASCII text
$ echo 'file ficheros' | sed 's/ficheros/f g/'
file f g
$ echo 'file ficheros' | sed 's/ficheros/f g/e'
f: ASCII text
g: ASCII text
$ echo 'file ficheros' | sed 's/ficheros/f g/ ; s/.*/\U&/'
FILE F G
$ echo 'file ficheros' | sed 's/ficheros/f g/e ; s/.*/\U&/'
F: ASCII TEXT
G: ASCII TEXT
$ echo 'file ficheros' | sed 's/u/f g/e'
file ficheros

En el último comando del ejemplo se ve que si no hay sustitución, no hay ejecución.

Si se mezcla con el modificador p, el orden en el que se escriban los modificadores es importante, pues los resultados son diferentes.

$ echo 'file ficheros' | sed 's/ficheros/f g/e'
f: ASCII text
g: ASCII text
$ echo 'file ficheros' | sed 's/ficheros/f g/pe'
file f g
f: ASCII text
g: ASCII text
$ echo 'file ficheros' | sed 's/ficheros/f g/ep'
f: ASCII text
g: ASCII text
f: ASCII text
g: ASCII text

Modificador M, m (multiline, extensión GNU) del comando s

Este modificador hace que las expresiones regulares casen en modo múltilinea, utilizando los cuatro metacaracteres vistos anteriormente y los operadores de repetición casarán dentro de una línea y no dentro de toda la zona de trabajo.

Veamos unos cuantos ejemplos para entenderlo mejor:

$ echo "file f g" | sed "s/f/f/e ; s/^/inicio - / ; s/$/ - fin/"
inicio - f: ASCII text
g: ASCII text - fin
$ echo "file f g" | sed "s/f/f/e ; s/^/inicio - /m ; s/$/ - fin/m"
inicio - f: ASCII text - fin
g: ASCII text
$ echo "file f g" | sed "s/f/f/e ; s/^/inicio - /gm ; s/$/ - fin/mg"
inicio - f: ASCII text - fin
inicio - g: ASCII text - fin
$ echo 'file ficheros' | sed 's/ficheros/f g/e ; s/.*/\U&/m'
F: ASCII TEXT
g: ASCII text
$ echo 'file ficheros' | sed 's/ficheros/f g/e ; s/.*/\U&/mg'
F: ASCII TEXT
G: ASCII TEXT
$ echo 'file ficheros' | sed 's/ficheros/f g/e ; s/.*/\U&/'
F: ASCII TEXT
G: ASCII TEXT
$ echo 'file ficheros' | sed 's/ficheros/f g/e ; s/.*\n.*e/\U&/m'
F: ASCII TEXT
G: ASCII TExt
$ echo "file f g" | sed "s/f/f/e ; s/\\\`/inicio - /m ; s/\'/ - fin/m"
inicio - f: ASCII text
g: ASCII text - fin
$ echo "file f g" | sed "s/f/f/e ; s/\\\`/inicio - / ; s/\'/ - fin/"
inicio - f: ASCII text
g: ASCII text - fin