Documentos de Académico
Documentos de Profesional
Documentos de Cultura
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
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.
Sin embargo, poner un espacio después del comando n provoca un error de sintaxis.
Poner un espacio antes del comando d está bien.
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
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.
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.
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).
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
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"
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
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.
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.
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
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
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
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".
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>
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.
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
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
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.
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:
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
...
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
s / ˆ [9 // gs / ˆ
[ •] * // gs /
•//g
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.
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:
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"
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.
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
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.
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.
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
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
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.
************************************************** ****************
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.
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.
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
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.
Uso de Rh
.IP "\ fIfdesc \ fR" 15n
puntero al descriptor de archivo de base de datos.
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.
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
/ˆ•/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.
.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
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
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.