Está en la página 1de 52

55

En este capítulo:
• Acerca de la sintaxis de
los comandos sed
• Comentario
• Sustitución
• Eliminar
• Agregar, Insertar y
Cambiar
Comandos sed básicos • Lista
• Transformar m
• Impresión
• Número de línea de
impresión
• próximo
• Leer y escribir archivos

• Dejar

El conjunto de comandos sed consta de 25 comandos. En este capítulo, presentamos


cuatro nuevos comandos de edición: d (eliminar), a (agregar), i (insertar) yc (cambiar).
También buscamos formas de cambiar el control de flujo (es decir, determinar qué
comando se ejecuta a continuación) dentro de un script.

Acerca de la sintaxis de los comandos sed


Antes de mirar comandos individuales, hay un par de puntos para revisar sobre la sintaxis
de todos los comandos sed. Cubrimos la mayor parte de este material en el capítulo
anterior.

Una dirección de línea es opcional con cualquier comando. Puede ser un patrón descrito
como una expresión regular rodeada de barras, un número de línea o un símbolo de
dirección de suma de línea. La mayoría de los comandos sed pueden aceptar dos
direcciones separadas por comas que indican un rango de líneas. Para estos comandos,
nuestra convención es especificar:
[habla a]mando

Algunos comandos aceptan solo una dirección de línea única. No se pueden aplicar a un
rango de líneas. La convención para ellos es:
[dirección de línea]mando
78
Comentario 79

Recuerde también que los comandos se pueden agrupar en la misma dirección rodeando
la lista de comandos entre llaves:
habla a {
comando1
comando2
comando3
}

El primer comando se puede colocar en la misma línea con la llave de apertura, pero la
llave de cierre debe aparecer en su propia línea. Cada comando puede tener su propia
dirección y se permiten múltiples niveles de agrupación. Además, como puede ver en la
sangría de los comandos dentro de las llaves, se permiten espacios y tabulaciones al
comienzo de las líneas.

Cuando sed no puede entender un comando, imprime el mensaje "Comando confuso". Un


error de sintaxis sutil es agregar un espacio después de un comando. Esto no esta
permitido; El final de un comando debe estar al final de la línea.
Una de las características de esta restricción es una característica "no documentada": se
pueden colocar múltiples comandos sed en la misma línea si cada uno está separado por
**
un punto y coma. El siguiente ejemplo es sintácticamente correcto:
Dakota del Norte

Sin embargo, poner un espacio después del comando n provoca un error de sintaxis.
Poner un espacio antes del comando d está bien.

Se desaconseja colocar múltiples comandos en la misma línea porque las secuencias de


comandos sed son lo suficientemente difíciles de leer incluso cuando cada comando se
escribe en su propia línea. (Tenga en cuenta que los comandos cambiar, insertar y agregar
deben especificarse en varias líneas y no pueden especificarse en la misma línea).

Comentario
Puede usar un comentario para documentar un guión describiendo su propósito. A partir
de este capítulo, nuestros ejemplos completos de guiones comienzan con una línea de
comentarios. Una línea de comentario puede aparecer como la primera línea de un script.
En la versión de sed del Sistema V, solo se permite un comentario en la primera línea. En
algunas versiones, incluida la ejecución de sed bajo SunOS 4.1.xy con GNU sed, puede
colocar comentarios en cualquier parte del script, incluso en una línea que sigue un
comando. Los ejemplos en este libro seguirán el caso más restrictivo del Sistema V sed,
limitando los comentarios a la primera línea del guión. Sin embargo, la capacidad de
utilizar comentarios para documentar su secuencia de comandos es valiosa y debe
utilizarla si su versión de sed lo permite.
* Sorprendentemente, el uso de punto y coma para separar comandos no está documentado en el estándar POSIX.
80 Capítulo 5: Comandos sed básicos

Un octothorpe (#) debe ser el primer personaje de la línea. La sintaxis de una línea de
comentario es:

#[norte]
El siguiente ejemplo muestra la primera línea de un script:
# wstar.sed: convierte archivos de WordStar

Si es necesario, el comentario puede continuar en varias líneas terminando la línea


**
anterior con una barra diagonal inversa. Por coherencia, puede comenzar la línea de
continuación con un # para que el propósito de la línea sea obvio.

Si el siguiente carácter que sigue a # es n, el script no producirá automáticamente una


salida. Es equivalente a especificar la opción de línea de comandos -n. El resto de la línea
que sigue a la n se trata como un comentario. Según el estándar POSIX, #n utilizado de
esta manera debe ser los dos primeros caracteres del archivo.

Sustitución
Ya hemos demostrado muchos usos del comando sustituto. Echemos un vistazo a su
sintaxis:
[habla a] s /modelo/ /reemplazo/ /banderas
Donde las banderas que modifican la sustitución son:

n Un número (1 a 512) que indica que se debe hacer un reemplazo solo por la enésima
aparición del patrón n.
g Realice cambios a nivel mundial en todas las ocurrencias en el espacio del patrón.
Normalmente solo se reemplaza la primera aparición.
p Imprime el contenido del espacio del patrón.
w archivo
Escriba el contenido del espacio del patrón para archivar.

El comando sustituto se aplica a las líneas que coinciden con la dirección. Si no se


especifica ninguna dirección, se aplica a todas las líneas que coinciden con el patrón n,
una expresión regular. Si se proporciona una expresión regular como una dirección, y no
se especifica ningún patrón n, el comando sustituto coincide con lo que coincide con la
dirección. Esto puede ser útil cuando el comando sustituto es uno de los múltiples
comandos aplicados en la misma dirección. Para ver un ejemplo, consulte la sección
"Cómo retirar páginas de referencia" más adelante en este capítulo.
* Sin embargo, esto no funciona con GNU sed (versión 2.05).
Sustitución 81

A diferencia de las direcciones, que requieren una barra inclinada (/) como delimitador, la
expresión regular puede delimitarse con cualquier carácter, excepto una nueva línea. Por
lo tanto, si el patrón contenía barras, puede elegir otro carácter, como un signo de
exclamación, como delimitador.

s! / usr / mail! / usr2 / mail!

Tenga en cuenta que el delimitador aparece tres veces y se requiere después del
reemplazo. Independientemente del delimitador que use, si aparece en la expresión
regular o en el texto de reemplazo, use una barra invertida (\) para escapar de ella.

Érase una vez, las computadoras almacenaban texto en registros de longitud fija. Una
línea terminó después de tantos caracteres (típicamente 80), y luego comenzó la siguiente
línea. No había un carácter explícito en los datos para marcar el final de una línea y el
comienzo de la siguiente; cada línea tenía el mismo número (fijo) de caracteres. Los
sistemas modernos son más flexibles; usan un carácter especial (denominado nueva línea)
para marcar el final de la línea. Esto permite que las líneas sean arbitrarias * * longitud.

Como la nueva línea es solo otro carácter cuando se almacena internamente, una
expresión regular puede usar "\ n" para que coincida con una nueva línea incrustada. Esto
ocurre, como verá en el próximo capítulo, en el caso especial cuando se agrega otra línea
a la línea actual en el espacio del patrón. (Consulte el Capítulo 2, Descripción de las
operaciones básicas, para una discusión sobre el direccionamiento de línea y el Capítulo
3, Descripción de la sintaxis de expresión regular, para una discusión sobre la sintaxis de
expresión regular).

El reemplazo es una cadena de caracteres que reemplazará lo que coincide con la


expresión regular. (Consulte la sección "El alcance del partido" en el Capítulo 3.) En
elreemplazo sección, solo los siguientes caracteres tienen un significado especial:
& Reemplazado por la cadena que coincide con la expresión regular.
\ n Coincide con la enésima subcadena (n es un solo dígito) previamente especificada
enmodelo utilizando "\ (" y "\)".
\ Se usa para escapar del ampersand (&), la barra diagonal inversa (\) y el delimitador del
comando de sustitución cuando se usan literalmente en la sección de reemplazo.
Además, se puede usar para escapar de la nueva línea y crear una cadena de
reemplazo multilínea.

Por lo tanto, además de los metacaracteres en las expresiones regulares, sed también tiene
metacaracteres en el reemplazo. Consulte la siguiente sección, "Metacaracteres de
reemplazo", para ver ejemplos de cómo usarlos.

Banderas se puede usar en combinación donde tenga sentido. Por ejemplo, gp realiza la
sustitución globalmente en la línea e imprime la línea. La bandera global es de lejos
* Bueno, mas o menos. Muchos programas de UNIX tienen límites internos en la longitud de las líneas que
procesarán. Sin embargo, la mayoría de los programas GNU no tienen tales límites.
82 Capítulo 5: Comandos sed básicos

El más utilizado. Sin él, el reemplazo se realiza solo para la primera aparición en la línea.
El indicador de impresión y el indicador de escritura proporcionan la misma
funcionalidad que los comandos de impresión y escritura (que se analizan más adelante
en este capítulo) con una diferencia importante. Estas acciones dependen de que ocurra
una sustitución exitosa. En otras palabras, si se realiza el reemplazo, la línea se imprime o
se escribe en el archivo. Debido a que la acción predeterminada es pasar a través de todas
las líneas, independientemente de si se toma alguna acción, los indicadores de impresión
y escritura generalmente se usan cuando se suprime la salida predeterminada (la opción
-n). Además, si un script contiene múltiples comandos sustitutos que coinciden con la
misma línea, varias copias de esa línea se imprimirán o escribirán en el archivo.

El indicador numérico se puede usar en los casos excepcionales en los que la expresión
regular se repite en una línea y el reemplazo debe hacerse solo para uno de esos casos por
posición. Por ejemplo, una línea, que tal vez contenga entrada tbl, podría contener
múltiples pestañas. Supongamos que hay tres pestañas por línea y desea reemplazar la
segunda pestaña con ">". El siguiente comando sustituto lo haría:
s / • /> / 2

"•" representa un carácter de tabulación real, que de otro modo es invisible en la pantalla.
Si la entrada es un archivo de una línea como el siguiente:
Columna1 • Columna2 • Columna3 • Columna4

el resultado producido al ejecutar el script en este archivo será:


Columna1 • Columna2> Columna3 • Columna4

Tenga en cuenta que sin la bandera numérica, el comando sustituto reemplazaría solo la
primera pestaña. (Por lo tanto, e "1" puede considerarse el indicador numérico
predeterminado).

Metacaracteres de reemplazo
Los metacaracteres de reemplazo son barra invertida (\), ampersand (&) y \ n. La barra
invertida generalmente se usa para escapar de los otros metacaracteres, pero también se
usa para incluir una nueva línea en una cadena de reemplazo.

Podemos hacer una variación en el ejemplo anterior para reemplazar la segunda pestaña
en cada línea con una nueva línea.
s/•/\
/2

Tenga en cuenta que no se permiten espacios después de la barra invertida. Este script
produce el siguiente resultado:
Columna1 • Columna2
Columna3 • Columna4
Sustitución 83

Otro ejemplo proviene de la conversión de un archivo para trof f a una entrada ASCII
para mat para Ventura Publisher. Convierte la siguiente línea para trof f:
.Ah "Gran rumbo"

a una línea similar para Ventura Publisher:


@A HEAD = Encabezado principal

El giro en este problema es que la línea debe ir precedida y seguida de líneas en blanco.
Es un ejemplo de escritura de una cadena de reemplazo multilínea.
/ˆ\.Ah/ {
s / \. Ah * / \
\
@A HEAD = /
s / "// g
s/$/\
//
}

El primer comando sustituto reemplaza ".Ah" con dos líneas nuevas y "@A HEAD =".
Una barra invertida al final de la línea es necesaria para escapar de la nueva línea. La
segunda sustitución elimina las comillas. El último comando coincide con el final de la
línea en el espacio del patrón (no con las nuevas líneas incrustadas) y agrega una nueva
línea después.

En el siguiente ejemplo, la barra invertida se usa para escapar del signo de encrucijado,
que aparece literalmente en la sección de reemplazo.
s / ORA / O'Reilly \ & Associates, Inc./g

Es fácil olvidarse del ampersand que aparece literalmente en la cadena de reemplazo. Si


no hubiéramos escapado en este ejemplo, el resultado hubiera sido "O'Reilly ORA
Associates, Inc."

Como metacarácter, el signo y (&) representa la extensión de la coincidencia del patrón,


no la línea que coincidió. Puede utilizar el signo de unión para hacer coincidir una
palabra y rodearla con trof solicitudes. El siguiente ejemplo rodea una palabra con
solicitudes de tamaño en puntos:

s / UNIX / \\ s-2 y \\ s0 / g

Debido a que las barras invertidas también son metacaracteres de reemplazo, se necesitan
dos barras invertidas para generar una barra invertida única. El "&" en la cadena de
reemplazo se refiere a "UNIX". Si la línea de entrada es:
en el sistema operativo UNIX.

entonces el comando sustituto produce:


en el sistema operativo \ s-2UNIX \ s0.
84 Capítulo 5: Comandos sed básicos

El signo y es particularmente útil cuando la expresión regular coincide con las


variaciones de una palabra. Le permite especificar una cadena de reemplazo variable que
corresponde a lo que realmente coincidió. Por ejemplo, supongamos que desea rodear con
paréntesis cualquier referencia cruzada a una sección numerada en un documento. En
otras palabras, cualquier referencia como "Ver Sección 1.4" o "Ver Sección 12.9" debe
aparecer entre paréntesis, como "(Ver Sección 12.9)". Una expresión regular puede
coincidir con la combinación diferente de números, por lo que usamos "&" en la cadena
de reemplazo y rodeamos lo que coincida.

s / Consulte la Sección [1-9] [0-9] * \. [1-9] [0-9] * / (&) /

El ampersand permite hacer referencia a la coincidencia completa en la cadena de


reemplazo.

Ahora veamos los metacaracteres que nos permiten seleccionar cualquier parte individual
de una cadena que coincida y recuperarla en la cadena de reemplazo. Se utilizan un par
de paréntesis escapadas para encerrar cualquier parte de una expresión regular y
guardarla para recuperarla. Se permiten hasta nueve "salvados" para una sola línea. "\ N"
se utiliza para recuperar la parte de la coincidencia que se guardó, donde n es un número
del 1 al 9 que hace referencia a una cadena particular "guardada" en orden de uso.

Por ejemplo, para poner los números de sección en negrita cuando aparecían como
referencias cruzadas, podríamos escribir la siguiente sustitución:
s / \ (Ver sección \) \ ([1-9] [0-9] * \. [1-9] [0-9] * \) / \ 1 \\ fB \ 2 \\ fP /

Se especifican dos pares de paréntesis escapados. Las primeras capturas "Ver sección
"(Debido a que esta es una cadena fija, podría simplemente haberse reescrito en la cadena
de reemplazo). El segundo captura el número de sección. La cadena de reemplazo
recuerda la primera subcadena guardada como "\ 1" y la segunda como "\ 2", que está
rodeada por solicitudes de fuente en negrita.

Podemos usar una técnica similar para unir partes de una línea e intercambiarlas. Por
ejemplo, supongamos que hay dos partes de una línea separadas por dos puntos. Podemos
unir cada parte, ponerlas entre paréntesis y cambiarlas en el reemplazo.

$ prueba de gato1 primero: segundo uno: dos


$ sed 's / \ (. * \): \ (. * \) / \ 2: \ 1 /' test1 segundo: primero

dos uno
El punto más importante es que puede recuperar una subcadena guardada en cualquier
orden y varias veces, como verá en el siguiente ejemplo.
Sustitución 85

Corregir entradas de índice


Más adelante, en la sección awk de este libro, presentaremos un programa para formatear
un índice, como el de este libro. El primer paso para crear un índice es colocar códigos de
índice en los archivos del documento. Utilizamos una macro de índice llamada .XX, que
toma un solo argumento, la entrada de índice. Una entrada de índice de muestra podría
ser:
.XX "sed, comando de sustitución"

Cada entrada de índice aparece en una línea por sí misma. Cuando ejecuta un índice,
obtiene una colección de entradas de índice con números de página que luego se ordenan
y combinan en una lista. Un editor que examina detenidamente esa lista generalmente
encontrará errores e inconsistencias que deben corregirse. En resumen, es difícil tener que
rastrear el archivo donde reside una entrada de índice y luego hacer la corrección,
particularmente cuando hay docenas de entradas para corregir.

Sed puede ser de gran ayuda para realizar estas ediciones en un grupo de archivos. Uno
puede simplemente crear una lista de ediciones en un script sed y luego ejecutarla en
todos los archivos. Un punto clave es que el comando sustituto necesita una dirección que
lo limite a líneas que comienzan con ".XX". Su secuencia de comandos no debe realizar
cambios en el texto en sí.

Digamos que queríamos cambiar la entrada de índice anterior a "sed, comando sustituto".
El siguiente comando lo haría:
/ˆ\.XX / s / sed, comando de sustitución / sed, comando de sustitución /

La dirección coincide con todas las líneas que comienzan con ".XX" y solo en esas líneas
intenta hacer el reemplazo. Quizás se pregunte, ¿por qué no especificar una expresión
regular más corta? Por ejemplo:
/ˆ\.XX / s / sustitución / sustituto /

La respuesta es simplemente que podría haber otras entradas que utilicen la palabra
"sustitución" correctamente y que no quisiéramos cambiar.

Podemos ir un paso más allá y proporcionar un script de shell que crea una lista de
entradas de índice preparadas para editar como una serie de comandos sustitutos sed.
#! / bin / sh
# index.edit: compila la lista de entradas de índice para editar. grep "ˆ \ .XX" $ * | sort -u |
sed '
s / ˆ \ .XX \ (. * \) $ / \ / ˆ \\. XX \ / s \ / \ 1 \ / \ 1 \ // '

El script de shell index.edit usa grep para extraer todas las líneas que contienen entradas
de índice de cualquier número de archivos especificados en la línea de comando. Pasa
esta lista a través de sor t que, con la opción -u, ordena y elimina las entradas duplicadas.
La lista se canaliza a sed y el script sed de una línea crea un comando de sustitución.
86 Capítulo 5: Comandos sed básicos

Miremos más de cerca. Aquí está solo la expresión regular:


ˆ \ .XX \ (. * \) $

Coincide con la línea completa, guardando la entrada de índice para recuperarla. Aquí
está solo la cadena de reemplazo:
\ / ˆ \\. XX \ / s \ / \ 1 \ / \ 1 \ /

Genera un comando sustituto que comienza con una dirección: una barra diagonal,
seguida de dos barras diagonales inversas, para generar una barra diagonal inversa para
proteger el punto en el ".XX" que sigue, luego aparece un espacio, luego otra barra
diagonal para completar la dirección. A continuación, mostramos una "s" seguida de una
barra diagonal, y luego recuperamos la porción guardada para usarla como una expresión
regular. Esto es seguido por otra barra y nuevamente recordamos la subcadena guardada
como la cadena de reemplazo. Una barra finalmente termina el comando.
Cuando el script index.edit se ejecuta en un archivo, crea una lista similar a esta:
$ index.edit ch05
/ˆ\.XX / s / "agregar comando (a)" / "agregar comando (a)" /
/ˆ\.XX / s / "cambiar comando" / "cambiar comando" / /ˆ\.XX / s /
"comando de cambio (c)" / "comando de cambio (c)" /
/ˆ\.XX / s / "comandos: sed, resumen de los comandos" / ": sed, resumen de" / /ˆ\.XX
/ s / "comando de eliminación (d)" / "comando de eliminación (d)" / /ˆ\.XX / s /
"comando de inserción (i)" / "comando de inserción (i)" /
/ˆ\.XX / s / "números de línea: impresión" / "números de línea:
impresión" / /ˆ\.XX / s / "comando de lista (l)" / "comando de lista (l)" /

Esta salida podría capturarse en un archivo. Luego puede eliminar las entradas que no
necesitan cambiar y puede hacer cambios editando la cadena de reemplazo. En ese
momento, puede usar este archivo como un script sed para corregir las entradas de índice
en todos los archivos de documentos.

Al hacer un libro grande con muchas entradas, puede usar grep nuevamente para extraer
entradas particulares de la salida de index.edit y dirigirlas a su propio archivo para su
edición. Esto le ahorra tener que atravesar numerosas entradas.

Hay un pequeño error en este programa. Debe buscar metacaracteres que puedan aparecer
literalmente en las entradas de índice y protegerlos en expresiones regulares. Por ejemplo,
si una entrada de índice contiene un asterisco, no se interpretará como tal, sino como un
metacarácter. Para hacer ese cambio efectivamente se requiere el uso de varios comandos
avanzados, por lo que pospondremos la impresión de este script hasta el próximo
capítulo.

Eliminar
Anteriormente mostramos ejemplos del comando de eliminación (d). Toma una dirección
y elimina el contenido del espacio del patrón si la línea coincide con la dirección.
Agregar, Insertar y Cambiar 87

El comando eliminar también es un comando que puede cambiar el flujo de control en un


script. Esto se debe a que una vez que se ejecuta, no se ejecutan más comandos en el
* *
espacio de patrón "vacío". El comando eliminar hace que se lea una nueva línea de
entrada y que un nuevo paso en el guión de edición comience desde arriba. (En este
comportamiento, es el mismo que el siguiente comando, que encontrará más adelante en
este capítulo).

Lo importante a recordar es: si la línea coincide con la dirección, se elimina toda la línea,
no solo la parte de la línea que coincide. (Para eliminar una parte de una línea, use el
comando sustituto y especifique un reemplazo vacío.) En el capítulo anterior, mostramos
un comando para eliminar líneas en blanco:
/ˆ$/d

Otro uso del comando eliminar podría ser eliminar ciertas solicitudes de trof f, como las
que agregan espacios, rompen la página y activan y desactivan el modo de relleno:
/ˆ\.Sp/d
/ˆ\.Bp/d
/ˆ\.Nf/d
/defensor

Estos comandos eliminan una línea completa. Por ejemplo, el primer comando eliminará
la línea ".sp 1" o ".sp .03v".

El comando eliminar se puede usar para eliminar un rango de líneas. En el capítulo


anterior, e e es un ejemplo de eliminación de todas las tablas de un archivo eliminando
las líneas entre las macros .TS y .TE. También hay un comando de eliminación (D)
utilizado para eliminar una parte de un espacio de patrón multilínea. Este comando
avanzado se presenta en el próximo capítulo.

Agregar, Insertar y Cambiar


Los comandos append (a), insert (i) y change (c) proporcionan funciones de edición que
se realizan comúnmente con un editor interactivo, como vi. Puede resultarle extraño usar
estos mismos comandos para "ingresar" texto utilizando un editor no interactivo. La
sintaxis de estos comandos es inusual para sed porque deben especificarse en varias
líneas. La sintaxis sigue:
adjuntar [dirección de línea]una\
texto
Inser t [dirección de línea]yo\
texto
cambio [habla a]C\
texto
* La documentación de UNIX dice "no se intentan más comandos en el cadáver de una línea eliminada". Q.E.P.D
88 Capítulo 5: Comandos sed básicos

El comando de inserción coloca el texto proporcionado antes de la línea actual en el


espacio del patrón. El comando append lo coloca después de la línea actual. El comando
de cambio reemplaza el contenido del espacio del patrón con el texto proporcionado.

Cada uno de estos comandos requiere una barra diagonal inversa para escapar del primer
final de línea. lostextodebe comenzar en la siguiente línea. Para ingresar varias líneas de
texto, cada línea sucesiva debe terminar con una barra diagonal inversa, con la excepción
de la última línea. Por ejemplo, el siguiente comando de inserción inserta dos líneas de
texto en una línea que coincida con "<Dirección de Larry>":

/ <Dirección de Larry> / i \
4700 Cross Court \
French Lick, IN

Además, si el texto contiene una barra invertida literal, agregue una barra invertida
adicional para escapar.* *

Los comandos de agregar e insertar se pueden aplicar solo a una dirección de línea única,
no a un rango de líneas. El comando de cambio, sin embargo, puede abordar un rango de
líneas. En este caso, reemplaza todas las líneas de dirección con una sola copia del texto.
En otras palabras, elimina cada línea en el rango, pero el texto proporcionado se emite
solo una vez. Por ejemplo, el siguiente script, cuando se ejecuta en un archivo que
contiene un mensaje de correo:
/ ˆDe /, / ˆ $ / c \
<Encabezado de correo eliminado>

elimina todo el encabezado del mensaje de correo y lo reemplaza con la línea


"<Encabezado de correo eliminado>". Tenga en cuenta que verá el comportamiento
opuesto cuando el comando de cambio sea uno de un grupo de comandos, encerrados
entre llaves, que actúan en un rango de líneas. Por ejemplo, el siguiente script:
/ ˆDe /, / ˆ $ / {
s / ˆDe // p
C\
<Encabezado de correo eliminado>
}

mostrará "<Encabezado de correo eliminado>" para cada línea en el rango. Entonces,


mientras que el ejemplo anterior genera el texto una vez, este ejemplo lo generará 10
veces si hay 10 líneas en el rango.

El comando change borra el espacio del patrón, teniendo el mismo efecto en el espacio
del patrón que el comando delete. No se aplica ningún comando después del comando de
cambio en el script.

* La documentación original de UNIX dice que las pestañas o espacios iniciales en el texto suministrado
desaparecerán en la salida. Este es el caso en versiones anteriores, como SunOS 4.1.xy / usr / ucb / sed en Solaris.
System V y GNU sed no eliminan los espacios en blanco iniciales. Si desaparecen en su sistema, la solución es
colocar una barra diagonal inversa al comienzo de la línea, antes de la primera pestaña o espacio. La barra diagonal
inversa no se emite.
Agregar, Insertar y Cambiar 89

Los comandos insertar y agregar no afectan el contenido del espacio del patrón. El texto
suministrado no coincidirá con ninguna dirección en los comandos posteriores en el
script, ni esos comandos pueden afectar el texto. Independientemente de los cambios que
ocurran para alterar el espacio del patrón, el texto proporcionado se enviará de manera
adecuada. Esto también es cierto cuando se suprime la salida predeterminada: el texto
proporcionado se generará incluso si el espacio del patrón no lo es. Además, el texto
suministrado no afecta el contador de línea interna de sed.

Veamos un ejemplo del comando de inserción. Supongamos que deseamos obtener un


archivo local de macros en todos los archivos de un documento en particular. Además,
nos gustaría definir una cadena de encabezado de página que identifique el documento
como borrador. El siguiente script inserta dos nuevas líneas de texto antes de la primera
línea de un archivo:
1i \
.so macros \
.ds CH primer borrador

Después de que sed ejecuta este comando, el espacio del patrón permanece sin cambios.
El nuevo texto se genera antes de la línea actual. Un comando posterior no pudo coincidir
con éxito "macros" o "Primer borrador".

Una variación del ejemplo anterior muestra el comando append agregando una línea al
final de un archivo:
$a\
Fin del documento

$ Es un símbolo de direccionamiento de línea que coincide con la última línea de un


archivo. El texto proporcionado se generará después de la línea actual, por lo que se
convierte en la última línea de la salida. Tenga en cuenta que aunque solo se genera una
línea, el texto proporcionado debe comenzar en una línea por sí mismo y no puede estar
en la misma línea que el comando append.

El siguiente ejemplo muestra los comandos de inserción y adición utilizados en el mismo


script. La tarea aquí es agregar algunas solicitudes de trof f antes de la macro que
inicializa una lista, y varias después de la macro que cierra la lista.
/ ˆ \ .Ls / i \
.in 5n \
.sp .3
/pasto\
.in 0 \
.sp .3

El comando de inserción coloca dos líneas antes de la macro .Ls y el comando append
coloca dos líneas después de la macro .Le.
El comando de inserción se puede usar para poner una línea en blanco antes de la línea
actual, o el comando de agregar para poner una después, dejando la línea que la sigue en
blanco.
90 Capítulo 5: Comandos sed básicos

El comando de cambio reemplaza el contenido del espacio del patrón con el texto que
proporciona. En efecto, elimina la línea actual y coloca el texto proporcionado en su
lugar. Se puede usar cuando desea hacer coincidir una línea y reemplazarla por completo.
Digamos, por ejemplo, que un archivo contiene muchas solicitudes explícitas de espacio
de prueba con diferentes cantidades de espacio. Mira las siguientes series:
.sp 1.5
.sp
.sp 1
.sp 1.5v
.sp .3v
.sp 3

Si desea cambiar todos los argumentos a ".5", probablemente sea más fácil usar el
comando de cambio que intentar hacer coincidir todos los argumentos individuales y
hacer la sustitución adecuada.

/ ˆ \ .sp / c \
.sp .5

Este comando nos permite ignorar los argumentos y reemplazarlos independientemente


de lo que sean.

Lista
El comando de lista (l) muestra el contenido del espacio del patrón, mostrando los
caracteres que no se imprimen como códigos ASCII de dos dígitos. Es similar en función
al comando list (: l) en vi. Puede usar este comando para detectar caracteres "invisibles"
**
en la entrada.

$ prueba de gato / spchar


Aquí hay una cadena de caracteres especiales: ˆA ˆB ˆM ˆG

$ sed -n -e "l" prueba / spchar


Aquí hay una cadena de caracteres especiales: \ 01 \ 02 \ 15 \
07

$ # prueba con GNU sed también


$ gsed -n -e "l" prueba / spchar
Aquí hay una cadena de caracteres especiales: \ 01 \ 02 \ r \ a

Debido a que el comando de lista causa una salida inmediata, suprimimos la salida
predeterminada o obtendríamos copias duplicadas de las líneas.
* GNU sed muestra ciertos caracteres, como el retorno de carro n, utilizando las secuencias de escape ANSI C, en
lugar de octal recto. Presumiblemente, esto es más fácil de comprender para aquellos que están familiarizados con C
(o awk, como veremos más adelante en el libro).
Lista 91 91

No puede hacer coincidir un carácter con el valor ASCII (ni con los valores octales) en
**
sed. En cambio, debe encontrar una combinación de teclas en vi para producirla. Use
CTRL-V para citar el personaje. Por ejemplo, puede hacer coincidir un carácter ESC (ˆ [).
Mira el siguiente script:

# listar línea y reemplazar ˆ [con "Escape"


ls / ˆ [/ Escape /

Su e es un archivo de prueba de una línea:


The Great ˆ [es una película protagonizada por Steve McQueen.

La ejecución del script produce el siguiente resultado:


The Great \ 33 es una película protagonizada por Steve McQueen.
The Great Escape es una película protagonizada por Steve McQueen.

GNU sed produce esto:


The Great \ 1b es una película protagonizada por Steve McQueen.
The Great Escape es una película protagonizada por Steve McQueen.

El carácter ˆ [se creó en vi ingresando CTRL-V y luego presionando la tecla ESC.

Eliminación de caracteres no imprimibles


de archivos nroff
El formateador UNIX nrof f produce salidas para impresoras de línea y pantallas CRT.
Para lograr efectos especiales como negrita, genera el carácter seguido de un retroceso y
luego genera el mismo carácter nuevamente. Una muestra de ella vista con un editor de
texto podría verse así:

NˆHNˆHNˆHNAˆHAˆHAˆHAMˆHMˆHMˆHMEˆHEˆHEˆHE

que en negrita la palabra "NOMBRE". Hay tres sobreataques por cada salida de
personaje. Del mismo modo, el subrayado se logra al generar un guión bajo, un retroceso
y luego el carácter a subrayar. El siguiente ejemplo es la palabra "archivo" rodeada por
una secuencia para subrayarla.
_ˆHf_ˆHi_ˆHl_ˆHe

A veces puede ser necesario eliminar estos "efectos especiales" de impresión; quizás si le
dan este tipo de salida como un archivo fuente. La siguiente línea elimina las secuencias
para envalentonar y subrayar:
s / .ˆH // g
* Sin embargo, puedes hacer esto en awk.
92 Capítulo 5: Comandos sed básicos

Elimina cualquier carácter que precede al espacio de retroceso junto con el espacio de
retroceso en sí. En el caso de subrayar, "." coincide con el guión bajo; para envalentonar,
coincide con el personaje de ataque. Debido a que se aplica repetidamente, se eliminan
múltiples ocurrencias del carácter de sobrecarga, dejando un solo carácter para cada
secuencia. Tenga en cuenta que ˆH se ingresa en vi presionando CTRL-V seguido de
CTRL-H.

Una aplicación de muestra está "des-formateando" una página man producida por nrof f
**
que se encuentra en un sistema antiguo System V UNIX. Si desea acceder a las páginas
formateadas con un editor de texto, querrá obtener una versión limpia. (En muchos
sentidos, este es un problema similar al que resolvimos al convertir un archivo de
procesamiento de texto en el capítulo anterior). Una página man formateada capturada en
un archivo tiene este aspecto:
ˆ [9 quien (1) quien (1)
ˆ [9 NˆHNˆHNˆHNAˆHAˆHAˆHAMˆHMˆHMˆHMEˆHEˆHEˆHE
¿Quién, quién está en el sistema?
SˆHSˆHSˆHSYˆHYˆHYˆHYNˆHNˆHNˆHNOˆHOˆHOˆHOPˆHPˆHPˆHPSˆHSˆHSˆHSIˆHI
quien [-a] [-b] [-d] [-H] [-l] [-p] [-q] [-r] [-s] [-t] [-T] [-u]
[ _ˆHf_ˆHi_ˆHl_ˆHe]
quién soy
quién soy
DˆHDˆHDˆHDEˆHEˆHEˆHESˆHSˆHSˆHSCˆHCˆHCˆHCRˆHRˆHRˆHRIˆHIˆHIˆHIPˆHP
quién puede enumerar el nombre del usuario, la línea de terminal, el
tiempo de inicio de sesión, el tiempo transcurrido desde que se produjo la
actividad en la línea y el
...

Además de eliminar las secuencias de negrita y subrayado, hay secuencias de escape


extrañas que producen alimentaciones de formularios u otras funciones de impresora.
Puede ver la secuencia "ˆ [9" en la parte superior de la página de manual formateada. Esta
secuencia de escape simplemente se puede eliminar:
s / ˆ [9 // g

Una vez más, el carácter ESC se ingresa en vi escribiendo CTRL-V seguido de presionar
la tecla ESC. El número 9 es literal. También hay lo que parecen ser espacios iniciales
que proporcionan el margen izquierdo y la sangría. En un examen más detallado, resulta
que los espacios iniciales preceden al encabezado, como "NOMBRE", pero una sola
pestaña precede a cada línea de texto. Además, hay pestañas que aparecen
inesperadamente en el texto, que tienen que ver con cómo nrof f se optimiza para
mostrarse en una pantalla CRT.

Para eliminar el margen izquierdo y las pestañas no deseadas, agregamos dos comandos a
nuestros dos anteriores:
* Durante un tiempo, muchos proveedores de System V UNIX solo proporcionaron páginas de manual
preformadas. Esto permitió que el comando man mostrara información rápidamente, en lugar de tener que
formatearla, pero la falta de fuente de prueba para las páginas de manual dificultó la reparación de errores de
documentación. Afortunadamente, la mayoría de los proveedores de sistemas UNIX modernos suministran fuente
para sus manuales.
Transformar m 93

# sedman - deformat nroff-formatted manpage s / .ˆH // g

s / ˆ [9 // gs / ˆ
[ •] * // gs /
•//g

El tercer comando busca cualquier número de pestañas o espacios al comienzo de una


línea. (Una pestaña se representa con “•” y un espacio con “ ".) El último comando busca
una pestaña y la reemplaza con un solo espacio. La ejecución de este script en nuestro
ejemplo de salida de la página man produce un archivo que se ve así:

quien (1) quien (1)


NOMBRE
¿Quién, quién está en el sistema?
SINOPSIS
quien [-a] [-b] [-d] [-H] [-l] [-p] [-q] [-r] [-s] [-t] [-T]
[-u] [archivo]
quién soy
quién soy
DESCRIPCIÓN
quién puede enumerar el nombre del usuario, la línea de terminal, el tiempo
de inicio de sesión,
tiempo transcurrido desde que ocurrió la actividad en la línea, y el
...
Este script no elimina las líneas en blanco innecesarias causadas por la paginación.
Veremos cómo hacerlo en el próximo capítulo, ya que requiere una operación multilínea.

Transformar m
El comando transform es peculiar, no solo porque es el menos mnemónico de todos los
comandos sed. Este comando transforma cada carácter por posición en la cadena abc a su
**
equivalente en la cadena xyz. Su sintaxis sigue:
[habla a] y /a B C/ /xyz/ /

El reemplazo se realiza por posición del personaje. Por lo tanto, no tiene idea de una
"palabra". Por lo tanto, "a" se reemplaza por "x" en cualquier lugar de la línea,
independientemente de si es seguido o no por una "b". Un posible uso de este comando es
reemplazar las letras en minúsculas con sus equivalentes en mayúsculas.
y / abcdefghijklmnopqrstuvwxyz / ABCDEFGHIJKLMNOPQRSTUVWXYZ /

Este comando afecta a todo el contenido del espacio del patrón. Si desea convertir una
sola palabra en la línea de entrada, puede hacerlo utilizando el espacio de espera.
Consulte el Capítulo 6 para obtener más detalles sobre cómo usar el espacio de espera.
(El proceso no es
* Este comando está diseñado siguiendo el comando tr de UNIX, que traduce los caracteres. Este es un comando
útil por derecho propio; consulte su documentación local para más detalles. Indudablemente, el comando y de sed
habría sido nombrado t, si t no hubiera sido tomado (por el comando de prueba, vea el Capítulo 6, Comandos
avanzados de sed).
94 Capítulo 5: Comandos sed básicos

trivial: saca la línea a la palabra que desea cambiar, elimina esa parte de la línea, copia la
línea después de la palabra en el espacio de espera, transforma la palabra y luego agrega
el contenido del espacio de espera al patrón espacio.)

Impresión
El comando de impresión (p) hace que se imprima el contenido del espacio del patrón.
No borra el espacio del patrón ni cambia el flujo de control en el script. Sin embargo, se
usa con frecuencia antes de los comandos (d, N, b) que cambian el control de flujo. A
menos que se suprima la salida predeterminada (-n), el comando de impresión hará que se
emitan copias duplicadas de una línea. Se puede usar cuando se suprime la salida
predeterminada o cuando el control de flujo a través del programa evita llegar al final del
script.

Veamos un script que muestra cómo se puede usar el comando de impresión para
propósitos de depuración. Se utiliza para mostrar el aspecto de la línea antes de realizar
cambios.

#n Imprimir línea antes y después de los cambios.


/ˆ\.Ah/ {
pags
s / "// g
s / ˆ \ .Ah // p
}

Tenga en cuenta que el indicador de impresión se proporciona al comando sustituto. El


indicador print del comando sustituto difiere del comando print en que está condicionado
a una sustitución exitosa.
Su e es una muestra de la secuencia de comandos anterior:
$ sed -f sed.debug ch05
.Ah
"Comentario"
Comentario
.Ah "Sustitución"
Sustitución
.Ah "Eliminar"
Eliminar
.Ah "Agregar, insertar y cambiar"
Agregar, insertar y cambiar
. Ah Lista
"Lista"

Cada línea afectada se imprime dos veces.


Veremos ejemplos adicionales del comando de impresión en el próximo capítulo.
Consulte también el comando de impresión multilínea (P) en el próximo capítulo.
próximo 95

Pr int Número de línea


Un signo igual (=) después de una dirección imprime el número de línea de la línea
coincidente. A menos que suprima la salida automática de líneas, se imprimirán tanto el
número de línea como la línea misma. Su sintaxis es:
[dirección de línea] =
Este comando no puede operar en un rango de líneas.

Un programador puede usar esto para imprimir ciertas líneas en un archivo fuente. Por
ejemplo, la siguiente secuencia de comandos imprime el número de línea seguido de la
línea misma para cada línea que contiene una pestaña seguida de la cadena "si". Aquí está
el guión:
#n imprime el número de línea y la línea con la declaración if
/ Si/{
=
pags
}

Tenga en cuenta que #n suprime la salida predeterminada de las líneas. Ahora veamos
cómo funciona en un programa de muestra, random.c:

$ sed -f sedscr. = random.c 192

if (rand_type == TYPE_0) {
234
if (rand_type == TYPE_0) estado [-1] = rand_type;
236
si (n <BREAK_1) {
252
si (n <BREAK_3) {
274
if (rand_type == TYPE_0) estado [-1] = rand_type;

303
if (rand_type == TYPE_0) estado [-1] = rand_type;

Los números de línea pueden ser útiles para encontrar problemas informados por el
compilador, que generalmente enumera el número de línea.

próximo
El siguiente comando (n) genera el contenido del espacio del patrón y luego lee la
siguiente línea de entrada sin volver a la parte superior del script. Su sintaxis es:
[habla a]norte
El siguiente comando cambia el control de flujo normal, que no genera el contenido del
espacio del patrón hasta que se llega al final del script y que
96 Capítulo 5: Comandos sed básicos

siempre comienza en la parte superior del guión después de leer en una nueva línea. En
efecto, el siguiente comando hace que la siguiente línea de entrada reemplace la línea
actual en el espacio del patrón. Los comandos posteriores en el script se aplican a la línea
de reemplazo, no a la línea actual. Si la salida predeterminada no se ha suprimido, la línea
actual se imprime antes de que tenga lugar el reemplazo.

Veamos un ejemplo del siguiente comando en el que eliminamos una línea en blanco solo
cuando sigue un patrón que coincide con la línea anterior. En este caso, un escritor ha
insertado una línea en blanco después de una macro de encabezado de sección (.H1).
Queremos eliminar esa línea en blanco sin eliminar todas las líneas en blanco del archivo.
Aquí está el archivo de muestra:
.H1 "Sobre Egipto"

Napoleón, señalando a las Pirámides, dijo a sus tropas:


"Soldados, cuarenta siglos tienen sus ojos en ti".

El siguiente script elimina esa línea en blanco:


/ˆ\.H1/ {
norte
/ˆ$/d
}

Puede leer este script de la siguiente manera: “Haga coincidir cualquier línea que
comience con la cadena '.H1', luego imprima esa línea y lea en la línea siguiente. Si esa
línea está en blanco, elimínela ". Las llaves se usan para aplicar múltiples comandos en la
misma dirección.

En una secuencia de comandos más larga, debe recordar que los comandos que ocurren
antes del siguiente comando no se aplicarán a la nueva línea de entrada, ni los comandos
que ocurran después de que se apliquen a la línea de entrada anterior.

Verá ejemplos adicionales del comando n en el Capítulo 6, junto con una versión de
varias líneas de este comando.

Leer y escribir archivos


Los comandos de lectura (r) y escritura (w) le permiten trabajar directamente con
archivos. Ambos toman un solo argumento, el nombre de un archivo. La sintaxis sigue:
[dirección de línea] r archivo
[habla a] w archivo

El comando de lectura lee el contenido del archivo en el espacio del patrón después de la
línea de dirección. No puede operar en un rango de líneas. El comando de escritura
escribe el contenido del espacio del patrón en el archivo.
Leer y escribir archivos 97

Debe tener un espacio único entre el comando y el nombre del archivo. (Todo después de
ese espacio y hasta la nueva línea se considera el nombre del archivo. Por lo tanto, los
espacios iniciales o incrustados se convertirán en parte del nombre del archivo). El
comando de lectura no se quejará si el archivo no existe. El comando de escritura creará
un archivo si no existe; si el archivo ya existe, el comando de escritura lo sobrescribirá
cada vez que se invoque el script. Si hay varias instrucciones que escriben en el mismo
archivo en un script, cada comando de escritura se agrega al archivo. Además, tenga en
cuenta que solo puede abrir hasta 10 archivos por script.

El comando de lectura puede ser útil para insertar el contenido de un archivo en un lugar
particular en otro archivo. Por ejemplo, supongamos que hay un conjunto de archivos y
cada archivo debe cerrarse con la misma declaración de uno o dos párrafos. Un script sed
le permitiría mantener el cierre por separado mientras lo inserta según sea necesario, por
ejemplo, al enviar el archivo a la impresora.
sed '$ r cierre' $ * | pr | lp

El $ es un símbolo de direccionamiento que especifica la última línea del archivo. El


contenido del archivo llamado cierre se coloca después del contenido del espacio del
patrón y se emite con él. Este ejemplo no especifica un nombre de ruta, suponiendo que
el archivo esté en el mismo directorio que el comando. Un comando de propósito más
general debe usar la ruta completa.

Es posible que desee probar algunas peculiaridades del comando de lectura. Veamos el
siguiente comando:
/ ˆ <Lista de empresas> / r company.list

Es decir, cuando sed coincide con una línea que comienza con la cadena "<Company-
list>", agregará el contenido del archivo company.list al final de la línea coincidente.
Ningún comando posterior afectará las líneas leídas del archivo. Por ejemplo, no puede
realizar ningún cambio en la lista de empresas que ha leído en el archivo. Sin embargo,
los comandos que abordan la línea original funcionarán. El comando anterior podría ser
seguido por un segundo comando:

/ ˆ <Lista de empresas> / d

para borrar la línea original. De modo que si el archivo de entrada fuera el siguiente:
Para servicio, contacte a cualquiera de las siguientes compañías:
<Lista de empresas>
Gracias.

ejecutar el script de dos líneas produciría:


Para servicio, contacte a cualquiera de las siguientes compañías:
Aliado
muguete
Unido
Gracias.
98 Capítulo 5: Comandos sed básicos

Suprimir la salida automática, usando la opción -n o la sintaxis del script #n, evita que se
genere la línea original en el espacio del patrón, pero el resultado de un comando de
lectura sigue yendo a la salida estándar.

Ahora veamos ejemplos del comando de escritura. Un uso es extraer información de un


archivo y colocarla en su propio archivo. Por ejemplo, imagine que tenemos un archivo
que enumera los nombres de los vendedores alfabéticamente. Para cada persona, el
listado designa a cuál de las cuatro regiones está asignada la persona. Aquí hay una
muestra:
Adams, Henrietta Noreste
Banks, Freda Sur
Dennis, Jim Medio oeste
Garvey, Bill Noreste
Jeffries, Jane Oeste
Madison, Sylvia Medio oeste
Sommes, Tom Sur

Escribir un script para un archivo de siete líneas, por supuesto, es ridículo. Sin embargo,
un script de este tipo puede manejar tantos nombres como sea posible y es reutilizable.

Si todo lo que quisiéramos fuera extraer los nombres de una región en particular,
podríamos usar fácilmente grep para hacerlo. La ventaja de sed es que podemos dividir el
archivo en cuatro archivos separados en un solo paso. El siguiente script de cuatro líneas
lo hace:
/ Northeast $ / w region.northeast
/ South $ / w region.south
/ Midwest $ / w region.midwest
/ West $ / w region.west

Todos los nombres de vendedores asignados a la región Noreste se colocarán en un


archivo llamado region.northeast.

El comando de escritura escribe el contenido del espacio del patrón cuando se invoca el
comando, no cuando se alcanza el final del script. En el ejemplo anterior, podríamos
querer eliminar el nombre de la región antes de escribirlo en el archivo. Para cada caso,
podríamos manejarlo como lo mostramos para la región Noreste:
/ Noreste $ / {
s ///
w region.northeast
}

El comando sustituto coincide con el mismo patrón que la dirección y lo elimina. Existen
muchos usos diferentes para el comando de escritura; por ejemplo, podría usarlo en un
script para generar varias versiones personalizadas del mismo archivo fuente.
Leer y escribir archivos 99

Verificación de páginas de referencia


Al igual que muchos programas, un script sed a menudo comienza pequeño, y es simple
de escribir y de leer. Al probar el script, puede descubrir casos específicos para los que no
se aplican las reglas generales. Para dar cuenta de esto, agrega líneas a su script,
haciéndolo más largo, más complejo y más completo. Si bien la cantidad de tiempo que
pasa refinando su secuencia de comandos puede cancelar el tiempo ahorrado al no hacer
la edición manualmente, al menos durante ese tiempo su propio juego de manos
aparentemente ha ocupado su mente: “¡Mira! La computadora lo hizo.

Encontramos uno de estos problemas al preparar una copia formateada de las páginas de
comandos que el escritor había escrito como un archivo de texto sin ninguna información
de formato. Aunque los archivos no tenían códigos de formato, los encabezados se usaron
de manera consistente para identificar el formato de las páginas de comandos. A
continuación se muestra un archivo de muestra.
************************************************** ****************

NOMBRE: DBclose - cierra una base de datos

SINTAXIS:
vacío DBclose (fdesc)
DBFILE * fdesc;

USO:
fdesc - puntero al descriptor de archivo de base de datos

DESC:
DBclose () cierra un archivo cuando se le da su descriptor de archivo de base de
datos. Sus escrituras pendientes en ese archivo se completarán antes de que se cierre
el archivo. Se eliminan todos los bloqueos de actualización. * fdesc se vuelve
inválido.

Otros usuarios no se ven afectados cuando llama a DBclose (). Sus bloqueos de
actualización y escrituras pendientes no se modifican.

Tenga en cuenta que no hay un archivo predeterminado como el que hay en BASIC.
* fdesc debe especificar un archivo abierto.

DBclose () es análogo a la declaración CLOSE en BASIC.

DEVOLUCIONES:
No hay valor de retorno

************************************************** ****************
La tarea consistía en formatear este documento para la impresora láser, utilizando las
macros de encabezado de referencia que habíamos desarrollado. Debido a que tal vez
había cuarenta de estas páginas de comandos, habría sido un trabajo pesado revisar y
agregar códigos
100 Capítulo 5: Comandos sed básicos

manualmente. Sin embargo, debido a que había tantos, y aunque el escritor fue
generalmente consistente en ingresarlos, habría suficientes diferencias de un comando a
otro para haber requerido varios pases.

Examinaremos el proceso de construcción de este script sed. En cierto sentido, este es un


proceso de mirar cuidadosamente cada línea de un archivo de entrada de muestra y
determinar si se debe o no editar en esa línea. Luego miramos el resto del archivo para
ver si hay ocurrencias similares. Intentamos encontrar patrones específicos que marquen
las líneas o el rango de líneas que necesitan edición.

Por ejemplo, al observar la primera línea, sabemos que debemos eliminar la fila de
asteriscos que separa cada comando. Especificamos una dirección para cualquier línea
que comience y termine con un asterisco y buscamos cero o más asteriscos en el medio.
La expresión regular usa un asterisco como literal y como metacarácter:
/ ˆ \ * \ ** \ * $ / d

Este comando elimina líneas enteras de asteriscos en cualquier parte del archivo. Vimos
que se usaban líneas en blanco para separar párrafos, pero reemplazar cada línea en
blanco con una macro de párrafo causaría otros problemas. En muchos casos, las líneas
en blanco se pueden eliminar porque se ha proporcionado espacio en la macro. Este es un
caso en el que posponemos la eliminación o el reemplazo de líneas en blanco de manera
global hasta que hayamos tratado casos específicos. Por ejemplo, algunas líneas en
blanco separan las secciones etiquetadas, y podemos usarlas para definir el final de un
rango de líneas. El script, entonces, está diseñado para eliminar líneas en blanco no
deseadas como la última operación.

Las pestañas fueron un problema similar. Las pestañas se usaron para sangrar líneas de
sintaxis y, en algunos casos, después de los dos puntos después de una etiqueta, como
"NOMBRE". Nuestro primer pensamiento fue eliminar todas las pestañas
reemplazándolas con ocho espacios, pero había algunas pestañas que queríamos
mantener, como las que están dentro de la línea de sintaxis. Por lo tanto, eliminamos solo
casos específicos, pestañas al comienzo de las líneas y pestañas después de los dos
puntos.
/ ˆ • / s ///
/: • / s //: /

La siguiente línea que encontramos tiene el nombre del comando y una descripción.
NOMBRE: DBclose - cierra una base de datos

Necesitamos reemplazarlo con la macro .Rh 0. Su sintaxis es:


.Rh 0 "mando ""descripción"
Insertamos la macro al comienzo de la línea, eliminamos el guión y rodeamos los
argumentos con comillas.
/NOMBRE:/ {
s //. Rh 0 "/
s / - / "" /
Leer y escribir archivos 101

s / $ / "/
}

Podemos adelantarnos un poco aquí y ver qué hace esta parte de nuestro script en la línea
de muestra:
.Rh 0 "DBclose" "cierra una base de datos"

La siguiente parte que examinamos comienza con "SINTAXIS". Lo que tenemos que
hacer aquí es poner en la macro .Rh, más algunas solicitudes de trof f adicionales para
sangría, un cambio de fuente, y sin relleno y sin ajuste. (La sangría se requiere porque
eliminamos las pestañas al comienzo de la línea). Estas solicitudes deben ir antes y
después de las líneas de sintaxis, activando y desactivando las capacidades. Para hacer
esto, definimos una dirección que especifica el rango de líneas entre dos patrones, la
etiqueta y una línea en blanco. Luego, usando el comando de cambio, reemplazamos la
etiqueta y la línea en blanco con una serie de solicitudes de formato.

/ SYNTAX: /, / ˆ $ / {
/ SINTAXIS: / c \
.Rh Sintaxis \
.in + 5n \
.ft B \
.nf \
.n / A
/ˆ$/c\
.in -5n \
.ft R \
.fi \
.ad b
}

Siguiendo el comando de cambio, cada línea de entrada termina con una barra diagonal
inversa, excepto la última línea. Como efecto secundario del comando de cambio, la línea
actual se elimina del espacio del patrón.

La parte de USO es la siguiente, que consta de una o más descripciones de elementos


variables. Aquí queremos formatear cada elemento como un párrafo sangrado con una
etiqueta en cursiva colgante. Primero, sacamos la macro .Rh; luego buscamos líneas que
tienen dos partes separadas por una pestaña y un guión. Cada parte se guarda, usando la
barra diagonal inversa, y se recupera durante la sustitución.
/ USO: /, / ˆ $ / {
/ USO: / c \
Uso de Rh
/\(.*\)•- \ (. * \) / S //. IP "\\ fI \ 1 \\ fR" 15n \
\ 2. /
}
Este es un buen ejemplo del poder de las expresiones regulares. Miremos hacia adelante,
una vez más, y previsualicemos el resultado de la muestra.
102 Capítulo 5: Comandos sed básicos

Uso de Rh
.IP "\ fIfdesc \ fR" 15n
puntero al descriptor de archivo de base de datos.

La siguiente parte que encontramos es la descripción. Notamos que se usan líneas en


blanco en esta parte para separar los párrafos. Al especificar la dirección de esta porción,
usamos la siguiente etiqueta, "DEVOLUCIONES".
/ DESC: /, / DEVOLUCIONES / {
/ DESC: / i \
.LP
s / DESC: * $ /. Rh Descripción /
s / ˆ $ /. LP /
}

Lo primero que hacemos es insertar una macro de párrafo porque la sección de USO
anterior consistía en párrafos sangrados. (Podríamos haber utilizado el macr os de lista
variable del paquete -mm en la sección USAGE; si es así, insertaríamos el .LE en este
punto). Esto se hace solo una vez, por lo que está codificado para Etiqueta "DESC".
Luego sustituimos la etiqueta "DESC" con la macro .Rh y reemplazamos todas las líneas
en blanco en esta sección con una macro de párrafo.

Cuando probamos esta parte de la secuencia de comandos sed en nuestro archivo de


muestra, no funcionó porque había un solo espacio siguiendo la etiqueta DESC.
Cambiamos la expresión regular para buscar cero o más espacios siguiendo la etiqueta.
Aunque esto funcionó para el archivo de muestra, hubo otros problemas cuando usamos
una muestra más grande. El escritor fue inconsistente en su uso de la etiqueta "DESC".
Principalmente, ocurrió en una línea por sí mismo; a veces, sin embargo, se incluyó al
comienzo del segundo párrafo. Así que tuvimos que agregar otro patrón para lidiar con
este caso. Busca la etiqueta seguida de un espacio y uno o más caracteres.

s / DESC: * $ /. Rh Descripción /
s / DESC: \ (. * \) /. Rh Descripción \
\\ 1 /

En el segundo caso, la macro del encabezado de referencia se emite seguida de una nueva
línea.

The next section, labeled “RETURNS,” is handled in the same way as the SYNTAX
section.

We do make minor content changes, replacing the label “RETURNS” with “Return
Value” and consequently adding this substitution:
s/There is no return value\.*/None./
The very last thing we do is delete remaining blank lines.
/ˆ$/d
Reading and Writing Files 103

Our script is put in a file named refsed. Her e it is in full:


# refsed -- add formatting codes to reference pages /ˆ\*\**\*$/d

/ˆ•/s///
/:•/s//:/
/NAME:/ {
s//.Rh 0 "/ s/
- /" "/ s/$/"/

}
/SYNTAX:/,/ˆ$/ {
/SYNTAX:/c\
.Rh Syntax\
.in +5n\
.ft B\
.nf\
.na
/ˆ$/c\
.in -5n\
.ft R\
.fi\
.ad b
}
/USAGE:/,/ˆ$/ {
/USAGE:/c\
.Rh Usage
/\(.*\)•- \(.*\)/s//.IP "\\fI\1\\fR" 15n\
\2./
}
/DESC:/,/RETURNS/
{ /DESC:/i\
.LP
s/DESC: *$/.Rh Description/
s/DESC: \(.*\)/.Rh Description\
\1/
s/ˆ$/.LP/
}
/RETURNS:/,/ˆ$/ {
/RETURNS:/c\
.Rh "Return Value"
s/There is no return value\.*/None./
}
/ˆ$/d

As we have remarked, you should not have sed overwrite the original. It is best to redir
ect the output of sed to another file or let it go to the screen. If the sed script does not
work properly, you will find that it is generally easier to change the script and re-run it on
the original file than to write a new script to correct the pr oblems caused by a previous
run.

$ sed -f refsed refpage


.Rh 0 "DBclose" "closes a database"
.Rh Syntax
104 Chapter 5: Basic sed Commands

.in +5n
.ft B
.nf
.na
void DBclose(fdesc)
DBFILE *fdesc;
.in -5n
.ft R
.fi
.ad b
.Rh Usage
.IP "\fIfdesc\fR" 15n
pointer to database file descriptor.
.LP
.Rh Description
DBclose( ) closes a file when given its database file descriptor. Your pending writes
to that file will be completed before the file is closed. All of your update locks are
removed. *fdesc becomes invalid.

.LP
Other users are not effected when you call DBclose(). Their update locks and pending
writes are not changed. .LP

Note that there is no default file as there is in BASIC.


*fdesc must specify an open file.
.LP
DBclose( ) is analogous to the CLOSE statement in BASIC.
.LP
.Rh "Return Value"
None.

Quit
The quit command (q) causes sed to stop reading new input lines (and stop send-ing them
to the output). Its syntax is:
[line-address]q
It can take only a single-line address. Once the line matching addr ess is reached, the
*
script will be terminated. For instance, the following one-liner uses the quit command to
print the first 100 lines from a file:
$ sed ’100q’ test
...

It prints each line until it gets to line 100 and quits. In this regard, this command
functions similarly to the UNIX head command.

* You need to be very careful not to use q in any program that writes its edits back to the original file. After q is
executed, no further output is produced. It should not be used in any case where you want to edit the front of the file
and pass the remainder through unchanged. Using q in this case is a very danger ous beginner’s mistake.
Quit 105

Another possible use of quit is to quit the script after you’ve extracted what you want
from a file. For instance, in an application like getmac (pr esented in Chapter 4, Writing
sed Scripts ) ther e is some inefficiency in continuing to scan through a large file after sed
has found what it is looking for.

So, for example, we could revise the sed script in the getmac shell script as fol-lows:

sed -n "
/ˆ\.de *$mac/,/ˆ\.\.$/{
p
/ˆ\.\.$/q
}" $file

The grouping of commands keeps the line:


/ˆ\.\.$/q

fr om being executed until sed reaches the end of the macro we’r e looking for. (This line
by itself would terminate the script at the conclusion of the first macro definition.) The
sed program quits on the spot, and doesn’t continue through the rest of the file looking
for other possible matches.

Because the macro definition files are not that long, and the script itself not that complex,
the actual time saved from this version of the script is negligible. How-ever, with a very
large file, or a complex, multiline script that needs to be applied to only a small part of
the file, this version of the script could be a significant time-saver.

If you compare the following two shell scripts, you should find that the first one per
forms better than the second. The following simple shell program prints out the top 10
lines of a file and then quits:
for file
do
sed 10q $file
done

The next example also prints the first 10 lines using the print command and sup-pr essing
default output:
for file
do
sed -n 1,10p $file
done

If you haven’t already done so, you should practice using the commands pre-sented in
this chapter before going on to the advanced commands in the next chapter.

También podría gustarte