Los conceptos básicos del uso del Sed Stream Editor para manipular texto en Linux
Introducción
El comando sed
, abreviatura de stream editor, realiza operaciones de edición en el texto proveniente de una entrada estándar o un archivo. sed
edita línea por línea y de forma no interactiva.
Esto significa que usted toma todas las decisiones de edición mientras llama al comando, y sed
ejecuta las instrucciones automáticamente. Esto puede parecer confuso o poco intuitivo, pero es una forma muy poderosa y rápida de transformar texto, especialmente como parte de un script o flujo de trabajo automatizado.
Este tutorial cubrirá algunas operaciones básicas y le presentará la sintaxis requerida para operar este editor. Es casi seguro que nunca reemplazará su editor de texto regular con sed
, pero probablemente se convertirá en una adición bienvenida a su caja de herramientas de edición de texto.
Nota: este tutorial utiliza la versión GNU de sed
que se encuentra en Ubuntu y otros sistemas operativos Linux. Si está utilizando macOS, tendrá la versión BSD que tiene diferentes opciones y argumentos. Puede instalar la versión GNU de sed
con Homebrew utilizando brew install gnu-sed
.
Uso básico
sed
opera en un flujo de texto que lee desde un archivo de texto o desde una entrada estándar (STDIN). Esto significa que puede enviar la salida de otro comando directamente a sed para su edición, o puede trabajar en un archivo que ya ha creado.
También debe tener en cuenta que sed
envía todo a la salida estándar (STDOUT) de forma predeterminada. Eso significa que, a menos que sea redirigido, sed
imprimirá su salida en la pantalla en lugar de guardarla en un archivo.
El uso básico es:
- sed [options] commands [file-to-edit]
En este tutorial, utilizará una copia de la licencia de software BSD para experimentar con sed
. En Ubuntu, ejecute los siguientes comandos para copiar el archivo de licencia BSD en su directorio de inicio para que pueda trabajar con él:
- cd
- cp /usr/share/common-licenses/BSD .
Si no tiene una copia local de la licencia BSD, cree una usted mismo con este comando:
- cat << 'EOF' > BSD
- Copyright (c) The Regents of the University of California.
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. Neither the name of the University nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
- EOF
Usemos sed
para ver el contenido del archivo de licencia BSD. sed
envía sus resultados a la pantalla de forma predeterminada, lo que significa que puede usarlo como un lector de archivos sin pasarle comandos de edición. Prueba a ejecutar el siguiente comando:
- sed '' BSD
Verá la licencia BSD en la pantalla:
OutputCopyright (c) The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
...
...
Las comillas simples contienen los comandos de edición que pasa a sed
. En este caso, no le pasó nada, por lo que sed
imprimió cada línea que recibió en la salida estándar.
sed
puede usar una entrada estándar en lugar de un archivo. Canaliza la salida del comando cat
a sed
para producir el mismo resultado:
- cat BSD | sed ''
Verá la salida del archivo:
OutputCopyright (c) The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
. . .
. . .
Como puede ver, puede operar en archivos o flujos de texto, como los que se producen al canalizar la salida con el carácter de tubería (|)
, con la misma facilidad.
Líneas de impresión
En el ejemplo anterior, vio que la entrada pasada a sed
sin ninguna operación imprimiría los resultados directamente en la salida estándar.
Exploremos el comando print
explícito de sed
, que se especifica usando el carácter p
entre comillas simples.
Ejecute el siguiente comando:
- sed 'p' BSD
Verá cada línea del archivo BSD
impresa dos veces:
OutputCopyright (c) The Regents of the University of California.
Copyright (c) The Regents of the University of California.
All rights reserved.
All rights reserved.
Redistribution and use in source and binary forms, with or without
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
modification, are permitted provided that the following conditions
are met:
are met:
. . .
. . .
sed
imprime automáticamente cada línea de forma predeterminada, y luego le indicas que imprima líneas explícitamente con el comando \p, por lo que obtienes cada línea impresa dos veces.
Si examina la salida de cerca, verá que tiene la primera línea dos veces, seguida de la segunda línea dos veces, etc., lo que le indica que sed
opera con los datos línea por línea. Lee una línea, opera sobre ella y genera el texto resultante antes de repetir el proceso en la siguiente línea.
Puede limpiar los resultados pasando la opción -n
a sed
, que suprime la impresión automática:
- sed -n 'p' BSD
OutputCopyright (c) The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
. . .
. . .
Ahora volvemos a imprimir cada línea una vez.
Los ejemplos hasta ahora difícilmente pueden considerarse edición (a menos que desee imprimir cada línea dos veces...). A continuación, explorará cómo sed
puede modificar la salida dirigiéndose a secciones específicas de los datos de texto.
Uso de rangos de direcciones
Las direcciones le permiten dirigirse a partes específicas de un flujo de texto. Puede especificar una línea específica o incluso un rango de líneas.
Hagamos que sed
imprima la primera línea del archivo. Ejecute el siguiente comando:
- sed -n '1p' BSD
La primera línea se imprime en la pantalla:
OutputCopyright (c) The Regents of the University of California.
Al colocar el número 1
antes del comando de impresión, le indicaste a sed
el número de línea para operar. Puede imprimir fácilmente cinco líneas (no olvide el \-n):
- sed -n '1,5p' BSD
Verás este resultado:
OutputCopyright (c) The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
Acabas de dar un rango de direcciones a sed
. Si le das a sed
una dirección, solo ejecutará los comandos que siguen en esas líneas. En este ejemplo, le ha dicho a sed que imprima de la línea 1 a la línea 5. Podría haber especificado esto de otra manera dando la primera dirección y luego usando un desplazamiento para decirle a sed cuántas líneas adicionales debe viajar, así:
- sed -n '1,+4p' BSD
Esto dará como resultado el mismo resultado, porque le dijiste a sed
que comenzara en la línea 1 y luego operara también en las siguientes 4 líneas.
Si desea imprimir líneas alternas, especifique el intervalo después del carácter ~
. El siguiente comando imprime líneas alternas en el archivo BSD
, comenzando con la línea 1:
- sed -n '1~2p' BSD
Aquí está el resultado que verá:
OutputCopyright (c) The Regents of the University of California.
modification, are permitted provided that the following conditions
1. Redistributions of source code must retain the above copyright
2. Redistributions in binary form must reproduce the above copyright
documentation and/or other materials provided with the distribution.
may be used to endorse or promote products derived from this software
. . .
. . .
También puede usar sed
para eliminar texto de la salida.
Eliminación de texto
Puede realizar la eliminación de texto donde anteriormente especificaba la impresión de texto cambiando el comando p
al comando d
.
En este caso, ya no necesita el comando -n
porque sed
imprimirá todo lo que no se elimine. Esto le ayudará a ver lo que está pasando.
Modifique el último comando de la sección anterior para que sea
- sed '1~2d' BSD
El resultado es que ves todas las líneas que no te dieron la última vez:
OutputAll rights reserved.
Redistribution and use in source and binary forms, with or without
are met:
notice, this list of conditions and the following disclaimer.
notice, this list of conditions and the following disclaimer in the
3. Neither the name of the University nor the names of its contributors
without specific prior written permission.
. . .
. . .
Es importante tener en cuenta aquí que nuestro archivo fuente no se ve afectado. Todavía está intacto. Las ediciones se envían a nuestra pantalla.
Si queremos guardar nuestras ediciones, podemos redirigir la salida estándar a un archivo como este:
- sed '1~2d' BSD > everyother.txt
Ahora abre el archivo con cat
:
- cat everyother.txt
Verá el mismo resultado que vio en pantalla anteriormente:
OutputAll rights reserved.
Redistribution and use in source and binary forms, with or without
are met:
notice, this list of conditions and the following disclaimer.
notice, this list of conditions and the following disclaimer in the
3. Neither the name of the University nor the names of its contributors
without specific prior written permission.
. . .
. . .
El comando sed
no edita el archivo fuente de manera predeterminada, pero puede cambiar este comportamiento pasando la opción -i
, lo que significa \realizar ediciones en el lugar. Esto alterará el archivo fuente.
Advertencia: Usar el modificador -i
sobrescribirá el archivo original, por lo que debe usarlo con cuidado. Realice las operaciones sin el interruptor -i
primero y luego ejecute el comando nuevamente con -i
una vez que tenga lo que desea, cree una copia de seguridad del archivo original o redirija el salida a un archivo. Es muy fácil alterar accidentalmente el archivo original con el interruptor -i
.
Intentémoslo editando el archivo everyother.txt
que acabas de crear, en el lugar. Reduzcamos aún más el archivo eliminando una línea por medio
- sed -i '1~2d' everyother.txt
Si usa cat
para mostrar el archivo con cat everyother.txt
, verá que el archivo ha sido editado.
La opción -i
puede ser peligrosa. Afortunadamente, sed
te permite crear un archivo de respaldo antes de editarlo.
Para crear un archivo de respaldo antes de editarlo, agregue la extensión de respaldo directamente después de la opción \-i:
- sed -i.bak '1~2d' everyother.txt
Esto crea un archivo de respaldo con la extensión .bak
y luego edita el archivo original en el lugar.
A continuación, verá cómo usar sed
para realizar operaciones de búsqueda y reemplazo.
Sustitución de texto
Quizás el uso más conocido de sed
es sustituir texto. sed
puede buscar patrones de texto usando expresiones regulares y luego reemplazar el texto encontrado con otra cosa.
Puede obtener más información sobre las expresiones regulares siguiendo el Uso de expresiones regulares Grep para buscar patrones de texto en Linux.
En su forma más básica, puede cambiar una palabra por otra usando la siguiente sintaxis:
's/old_word/new_word/'
El s
es el comando sustituto. Las tres barras (/
) se utilizan para separar los diferentes campos de texto. Puede usar otros caracteres para delimitar los campos si le resulta más útil.
Por ejemplo, si estuviera tratando de cambiar el nombre de un sitio web, sería útil usar otro delimitador ya que las URL contienen barras.
Ejecute el siguiente comando para imprimir una URL con echo
y modificarla con sed
, utilizando el carácter de subrayado (_
) como delimitador:
- echo "http://www.example.com/index.html" | sed 's_com/index_org/home_'
Esto reemplaza com/index
con org/home
. El resultado muestra la URL modificada:
Outputhttp://www.example.org/home.html
No olvide el delimitador final, o sed
se quejará. Si ejecutó este comando:
- echo "http://www.example.com/index.html" | sed 's_com/index_org/home'
Verías este resultado:
Outputsed: -e expression #1, char 20: unterminated `s' command
Vamos a crear un nuevo archivo para practicar algunas sustituciones. Ejecute el siguiente comando para crear un nuevo archivo de texto llamado song.txt
:
- echo "this is the song that never ends
- yes, it goes on and on, my friend
- some people started singing it
- not knowing what it was
- and they'll continue singing it forever
- just because..." > song.txt
Ahora sustituyamos la expresión on
por forward
. Usa el siguiente comando:
- sed 's/on/forward/' song.txt
La salida se ve así:
Outputthis is the sforwardg that never ends
yes, it goes forward and on, my friend
some people started singing it
not knowing what it was
and they'll cforwardtinue singing it forever
just because...
Puedes ver algunas cosas notables aquí. Primero, es que sed
reemplazó patrones, no palabras. El on
dentro de song
se cambia a forward
.
La otra cosa a tener en cuenta es que en la línea 2, el segundo on
no se cambió a forward
.
Esto se debe a que, de manera predeterminada, el comando s
opera en la primera coincidencia de una línea y luego pasa a la siguiente línea. Para hacer que sed
reemplace cada instancia de on
en lugar de solo la primera en cada línea, debe pasar una marca opcional al comando de sustitución.
Proporcione el indicador g
al comando de sustitución colocándolo después del conjunto de sustitución:
- sed 's/on/forward/g' song.txt
Verás este resultado:
Outputthis is the sforwardg that never ends
yes, it goes forward and forward, my friend
some people started singing it
not knowing what it was
and they'll cforwardtinue singing it forever
just because...
Ahora el comando sustituto cambia cada instancia.
Si solo quisiera cambiar la segunda instancia de \on” que sed encuentra en cada línea, entonces usaría el número 2
en lugar de g
:
- sed 's/on/forward/2' song.txt
Esta vez, las otras líneas no cambian, ya que no tienen una segunda aparición:
Outputthis is the song that never ends
yes, it goes on and forward, my friend
some people started singing it
not knowing what it was
and they'll continue singing it forever
just because...
Si solo desea ver qué líneas se sustituyeron, use la opción -n
nuevamente para suprimir la impresión automática.
Luego puede pasar la opción p
al comando de sustitución para imprimir líneas donde se realizó la sustitución.
- sed -n 's/on/forward/2p' song.txt
La línea que cambió se imprime en la pantalla:
Outputyes, it goes on and forward, my friend
Como puede ver, puede combinar las banderas al final del comando.
Si desea que el proceso de búsqueda ignore las mayúsculas y minúsculas, puede pasarle el indicador \i.
- sed 's/SINGING/saying/i' song.txt
Aquí está el resultado que verá:
Outputthis is the song that never ends
yes, it goes on and on, my friend
some people started saying it
not knowing what it was
and they'll continue saying it forever
just because...
Reemplazar y hacer referencia al texto coincidente
Si desea encontrar patrones más complejos con expresiones regulares, tiene varios métodos diferentes para hacer referencia al patrón coincidente en el texto de reemplazo.
Por ejemplo, para hacer coincidir desde el principio de la línea con at
, use el siguiente comando:
- sed 's/^.*at/REPLACED/' song.txt
Verás este resultado:
OutputREPLACED never ends
yes, it goes on and on, my friend
some people started singing it
REPLACED it was
and they'll continue singing it forever
just because...
Puede ver que la expresión comodín coincide desde el principio de la línea hasta la última instancia de at
.
Como no sabe la frase exacta que coincidirá en la cadena de búsqueda, puede usar el carácter &
para representar el texto coincidente en la cadena de reemplazo.
Pongamos paréntesis alrededor del texto coincidente:
- sed 's/^.*at/(&)/' song.txt
Verás este resultado:
Output(this is the song that) never ends
yes, it goes on and on, my friend
some people started singing it
(not knowing what) it was
and they'll continue singing it forever
just because...
Una forma más flexible de hacer referencia al texto coincidente es usar paréntesis de escape para agrupar secciones de texto coincidente.
Cada grupo de texto de búsqueda marcado con paréntesis puede ser referenciado por un número de referencia con escape. Por ejemplo, se puede hacer referencia al primer grupo de paréntesis con
, al segundo con
y así sucesivamente.
En este ejemplo, cambiaremos las dos primeras palabras de cada línea:
- sed 's/\([a-zA-Z0-9][a-zA-Z0-9]*\) \([a-zA-Z0-9][a-zA-Z0-9]*\)/\2 \1/' song.txt
Verás este resultado:
Outputis this the song that never ends
yes, goes it on and on, my friend
people some started singing it
knowing not what it was
they and'll continue singing it forever
because just...
Como puedes ver, los resultados no son perfectos. Por ejemplo, la segunda línea salta la primera palabra porque tiene un carácter que no figura en nuestro conjunto de caracteres. De manera similar, trató a theyll
como dos palabras en la quinta línea.
Mejoremos la expresión regular para que sea más precisa:
- sed 's/\([^ ][^ ]*\) \([^ ][^ ]*\)/\2 \1/' song.txt
Verás este resultado:
Outputis this the song that never ends
it yes, goes on and on, my friend
people some started singing it
knowing not what it was
they'll and continue singing it forever
because... just
Esto es mucho mejor que la última vez. Esto agrupa la puntuación con la palabra asociada.
Observe cómo repetimos la expresión dentro de los paréntesis (una vez sin el carácter *
y luego otra vez con él). Esto se debe a que el carácter *
coincide con el conjunto de caracteres anterior cero o más veces. Esto significa que la coincidencia con el comodín se consideraría una coincidencia incluso si no se encuentra el patrón.
Para asegurarse de que sed
encuentre el texto al menos una vez, debe hacerlo coincidir una vez sin el comodín antes de emplear el comodín.
Conclusión
En este tutorial, exploró el comando sed
. Imprimió líneas específicas del archivo, buscó texto, eliminó líneas, sobrescribió el archivo original y usó expresiones regulares para reemplazar el texto. Ya debería poder ver cómo puede transformar rápidamente un documento de texto utilizando comandos sed construidos correctamente.
En el próximo artículo de esta serie, explorará algunas características más avanzadas.