Puede sonar loco, pero el Linux sed
es un editor de texto sin interfaz. Puede usarlo desde la línea de comandos para manipular texto en archivos y secuencias. Te mostraremos cómo aprovechar su poder.
¿De qué vamos a hablar?
El poder de la semilla
El sed
El comando es un poco como el ajedrez: se necesita una hora para aprender los conceptos básicos y toda una vida para dominarlos (o, al menos, mucha práctica). Te mostraremos una selección de gambitos de apertura en cada una de las principales categorías de sed
funcionalidad.
sed
es un editor de secuencias que funciona en entrada canalizada o archivos de texto. Sin embargo, no tiene una interfaz de editor de texto interactivo. Más bien, proporciona instrucciones para que siga a medida que funciona a través del texto. Todo esto funciona en Bash y otros shells de línea de comandos.
Con sed
puede hacer todo lo siguiente:
- Seleccionar texto
- Texto sustitutivo
- Agregar líneas al texto
- Eliminar líneas del texto
- Modificar (o conservar) un archivo original
Hemos estructurado nuestros ejemplos para introducir y demostrar conceptos, no para producir lo más terso (y menos accesible) sed
Comandos. Sin embargo, las funcionalidades de coincidencia de patrones y selección de texto de sed
dependen en gran medida de las expresiones regulares (regexes). Vas a necesitar cierta familiaridad con estos para obtener lo mejor de sed
.
Un ejemplo sencillo
Primero, vamos a usar echo
Para enviar algún mensaje de texto a sed
a través de una tubería, y tener sed
sustitúyase una parte del texto. Para ello, escribimos lo siguiente:
echo howtogonk | sed 's/gonk/geek/'
El echo
El comando envía “howtogonk” a sed
, y se aplica nuestra regla de sustitución simple (la “s” significa sustitución). sed
busca en el texto de entrada una aparición de la primera cadena y reemplazará las coincidencias con la segunda.
La cadena “gonk” se reemplaza por “geek” y la nueva cadena se imprime en la ventana del terminal.
Las sustituciones son probablemente el uso más común de sed
. Sin embargo, antes de que podamos profundizar en las sustituciones, necesitamos saber cómo seleccionar y hacer coincidir el texto.
Selección de texto
Vamos a necesitar un archivo de texto para nuestros ejemplos. Usaremos uno que contiene una selección de versos del poema épico de Samuel Taylor Coleridge “The Rime of the Ancient Mariner”.
Escribimos lo siguiente para echarle un vistazo con less
:
less coleridge.txt
Para seleccionar algunas líneas del archivo, proporcionamos las líneas de inicio y fin del rango que queremos seleccionar. Un solo número selecciona esa línea.
Para extraer las líneas del uno al cuatro, escribimos este comando:
sed -n '1,4p' coleridge.txt
Tenga en cuenta la coma entre 1
y 4
. El p
significa “imprimir líneas coincidedas”. De forma predeterminada, sed
imprime todas las líneas. Veríamos todo el texto en el archivo con las líneas coincidentes impresas dos veces. Para evitar esto, usaremos el -n
(silencioso) opción para suprimir el texto no comparado.
Cambiamos los números de línea para que podamos seleccionar un versículo diferente, como se muestra a continuación:
sed -n '6,9p' coleridge.txt
Podemos utilizar el -e
(expresión) opción para realizar múltiples selecciones. Con dos expresiones, podemos seleccionar dos versículos, así:
sed -n -e '1,4p' -e '31,34p' coleridge.txt
Si reducimos el primer número en la segunda expresión, podemos insertar un espacio en blanco entre los dos versículos. Escribimos lo siguiente:
sed -n -e '1,4p' -e '30,34p' coleridge.txt
También podemos elegir una línea de salida y contar sed
para recorrer el archivo e imprimir líneas alternativas, cada quinta línea, o para omitir cualquier número de líneas. El comando es similar a los que usamos anteriormente para seleccionar un rango. Esta vez, sin embargo, usaremos una tilde (~
) en lugar de una coma para separar los números.
El primer número indica la línea de partida. El segundo número dice sed
qué líneas después de la línea de salida queremos ver. El número 2 significa cada segunda línea, 3 significa cada tercera línea, y así sucesivamente.
Escribimos lo siguiente:
sed -n '1~2p' coleridge.txt
No siempre sabrá dónde se encuentra el texto que está buscando en el archivo, lo que significa que los números de línea no siempre serán de mucha ayuda. Sin embargo, también puede utilizar sed
para seleccionar líneas que contengan patrones de texto coincidentes. Por ejemplo, extraigamos todas las líneas que comienzan con “Y”.
El caret (^
) representa el inicio de la línea. Adjuntaremos nuestro término de búsqueda en barras diagonales (/
). También incluimos un espacio después de “Y” para que palabras como “Android” no se incluyan en el resultado.
Lectura sed
los guiones pueden ser un poco difíciles al principio. El /p
significa “imprimir”, tal como lo hizo en los comandos que usamos anteriormente. En el siguiente comando, aunque, una barra diagonal le precede:
sed -n '/^And /p' coleridge.txt
Tres líneas que comienzan con “Y” se extraen del archivo y se muestran para nosotros.
Hacer sustituciones
En nuestro primer ejemplo, te mostramos el siguiente formato básico para un sed
sustitución:
echo howtogonk | sed 's/gonk/geek/'
El s
Dice sed
se trata de una sustitución. La primera cadena es el patrón de búsqueda, y la segunda es el texto con el que queremos reemplazar ese texto coincidente. Por supuesto, como con todas las cosas de Linux, el diablo está en los detalles.
Escribimos lo siguiente para cambiar todas las ocurrencias de “día” a “semana”, y le damos al marinero y al albatros más tiempo para vincularse:
sed -n 's/day/week/p' coleridge.txt
En la primera línea, solo se cambia la segunda ocurrencia de “día”. Esto se debe a que sed
paradas después del primer partido por línea. Tenemos que añadir una “g” al final de la expresión, como se muestra a continuación, para realizar una búsqueda global para que se procesen todas las coincidencias en cada línea:
sed -n 's/day/week/gp' coleridge.txt
Esto coincide con tres de los cuatro en la primera línea. Porque la primera palabra es “Día”, y sed
no permite ubicarse en mayúsculas y minúsculas, no considera que esa instancia sea lo mismo que “día”.
Escribimos lo siguiente, agregando un i
al comando al final de la expresión para indicar la insensibilidad a mayúsculas y minúsculas:
sed -n 's/day/week/gip' coleridge.txt
Esto funciona, pero es posible que no siempre desee activar la insensibilidad de mayúsculas y minúsculas para todo. En esos casos, puede usar un grupo regex para agregar insensibilidad de casos específica del patrón.
Por ejemplo, si encerramos caracteres entre corchetes ([]
), se interpretan como “cualquier personaje de esta lista de personajes”.
Escribimos lo siguiente, e incluimos “D” y “d” en el grupo, para asegurarnos de que coincida con “Día” y “Día”:
sed -n 's/[Dd]ay/week/gp' coleridge.txt
También podemos restringir las sustituciones a secciones del archivo. Digamos que nuestro archivo contiene un espaciado extraño en el primer versículo. Podemos usar el siguiente comando familiar para ver el primer versículo:
sed -n '1,4p' coleridge.txt
Buscaremos dos espacios y los sustituiremos por uno. Haremos esto a nivel mundial para que la acción se repita en toda la línea. Para ser claros, el patrón de búsqueda es espacio, espacio asterisco (*
), y la cadena de sustitución es un único espacio. El 1,4
restringe la sustitución a las cuatro primeras líneas del archivo.
Ponemos todo eso junto en el siguiente comando:
sed -n '1,4 s/ */ /gp' coleridge.txt
¡Esto funciona muy bien! El patrón de búsqueda es lo importante aquí. El asterisco (*
) representa cero o más del carácter anterior, que es un espacio. Por lo tanto, el patrón de búsqueda está buscando cadenas de un espacio o más.
Si sustituimos un solo espacio por cualquier secuencia de espacios múltiples, devolveremos el archivo al espaciado regular, con un solo espacio entre cada palabra. Esto también sustituirá un solo espacio por un solo espacio en algunos casos, pero esto no afectará nada negativamente: aún obtendremos el resultado deseado.
Si escribimos lo siguiente y reducimos el patrón de búsqueda a un solo espacio, verás inmediatamente por qué tenemos que incluir dos espacios:
sed -n '1,4 s/ */ /gp' coleridge.txt
Debido a que el asterisco coincide con cero o más del carácter anterior, ve cada carácter que no es un espacio como un “espacio cero” y le aplica la sustitución.
Sin embargo, si incluimos dos espacios en el patrón de búsqueda, sed
debe encontrar al menos un carácter de espacio antes de aplicar la sustitución. Esto garantiza que los caracteres que no son espacios permanezcan intactos.
Escribimos lo siguiente, utilizando el -e
(expresión) que usamos anteriormente, lo que nos permite hacer dos o más sustituciones simultáneamente:
sed -n -e 's/motion/flutter/gip' -e 's/ocean/gutter/gip' coleridge.txt
Podemos lograr el mismo resultado si usamos un punto y coma (;
) para separar las dos expresiones, así:
sed -n 's/motion/flutter/gip;s/ocean/gutter/gip' coleridge.txt
Cuando cambiamos “día” por “semana” en el siguiente comando, la instancia de “día” en la expresión “bien al día” también se intercambió:
sed -n 's/[Dd]ay/week/gp' coleridge.txt
Para evitar esto, solo podemos intentar sustituciones en líneas que coincidan con otro patrón. Si modificamos el comando para que tenga un patrón de búsqueda al principio, solo consideraremos operar en líneas que coincidan con ese patrón.
Escribimos lo siguiente para hacer que nuestro patrón de coincidencia sea la palabra “después”:
sed -n '/after/ s/[Dd]ay/week/gp' coleridge.txt
Eso nos da la respuesta que queremos.
Sustituciones más complejas
Démosse un descanso a Coleridge y usemos sed
Para extraer nombres de la etc/passwd
archivo.
Hay formas más cortas de hacer esto (más sobre eso más adelante), pero usaremos la forma más larga aquí para demostrar otro concepto. Cada elemento coincidente en un patrón de búsqueda (llamado subexpresiones) se puede numerar (hasta un máximo de nueve elementos). A continuación, puede utilizar estos números en su sed
comandos para hacer referencia a subexpresiones específicas.
Tienes que adjuntar la subexpresión entre paréntesis [()
] para que esto funcione. Los paréntesis también deben ir precedidos de una barra diagonal hacia atrás (/
) para evitar que sean tratados como un carácter normal.
Para ello, debe escribir lo siguiente:
sed 's//([^:]*/).*//1/' /etc/passwd
Vamos a desglosar esto:
sed 's/
: Elsed
y el comienzo de la expresión de sustitución./(
: El paréntesis de apertura [(
] encerrando la subexpresión, precedida por una barra diagonal inversa (/
).[^:]*
: La primera subexpresión del término de búsqueda contiene un grupo entre corchetes. El caret (^
) significa “no” cuando se utiliza en un grupo. Un grupo significa cualquier carácter que no sea dos puntos (:
) será aceptado como partido./)
: El paréntesis de cierre [)
] con una barra diagonal inversa anterior (/
)..*
: Esta segunda subexpresión de búsqueda significa “cualquier carácter y cualquier número de ellos”.//1
: La parte de sustitución de la expresión contiene1
precedido por una barra diagonal inversa (/
). Esto representa el texto que coincide con la primera subexpresión./'
: La barra diagonal de cierre (/
) y cita única ('
) terminar elsed
mandar.
Lo que todo esto significa es que vamos a buscar cualquier cadena de caracteres que no contenga dos puntos (:
), que será la primera instancia de texto coincidente. Luego, estamos buscando cualquier otra cosa en esa línea, que será la segunda instancia de texto coincidente. Vamos a sustituir toda la línea por el texto que coincidía con la primera subexpresión.
Cada línea en el /etc/passwd
comienza con un nombre de usuario con dos puntos de usuario. Hacemos coincidir todo hasta los primeros dos puntos y luego sustituimos ese valor por toda la línea. Por lo tanto, hemos aislado los nombres de usuario.
A continuación, adjuntaremos la segunda subexpresión entre paréntesis. [()
] por lo que también podemos hacer referencia a él por número. También reemplazaremos /1
con /2
. Nuestro comando ahora sustituirá toda la línea con todo desde el primer colon (:
) al final de la línea.
Escribimos lo siguiente:
sed 's//([^:]*/)/(.*/)//2/' /etc/passwd
Esos pequeños cambios invierten el significado del comando, y obtenemos todo excepto los nombres de usuario.
Ahora, echemos un vistazo a la forma rápida y fácil de hacer esto.
Nuestro término de búsqueda es del primer colon (:
) al final de la línea. Porque nuestra expresión de sustitución está vacía (//
), no reemplazaremos el texto coincidenado con nada.
Entonces, escribimos lo siguiente, cortando todo desde el primer colon (:
) al final de la línea, dejando solo los nombres de usuario:
sed 's/:.*//" /etc/passwd
Veamos un ejemplo en el que hacemos referencia a la primera y segunda coincidencia en el mismo comando.
Tenemos un archivo de comas (,
) separando nombres y apellidos. Queremos enumerarlos como “apellido, nombre”. Podemos usar cat
, como se muestra a continuación, para ver lo que hay en el archivo:
cat geeks.txt
Como un montón de sed
comandos, este siguiente puede parecer impenetrable al principio:
sed 's/^/(.*/),/(.*/)€//2,/1 /g' geeks.txt
Este es un comando de sustitución como los otros que hemos utilizado, y el patrón de búsqueda es bastante fácil. Lo desglosaremos a continuación:
sed 's/
: El comando de sustitución normal.^
: Debido a que el cuidador no está en un grupo ([]
), significa “El comienzo de la línea”./(.*/),
: La primera subexpresión es cualquier número de caracteres. Está entre paréntesis [()
], cada uno de los cuales está precedido por una barra diagonal inversa (/
) para que podamos referenciarlo por número. Todo nuestro patrón de búsqueda hasta ahora se traduce como búsqueda desde el inicio de la línea hasta la primera coma (,
) para cualquier número de caracteres./(.*/)
: La siguiente subexpresión es (de nuevo) cualquier número de cualquier carácter. También está entre paréntesis. [()
], ambos precedidos por una barra diagonal inversa (/
) para que podamos hacer referencia al texto coincidente por número.€/
: El signo de dólar (€
) representa el final de la línea y permitirá que nuestra búsqueda continúe hasta el final de la línea. Hemos usado esto simplemente para introducir el signo de dólar. Realmente no lo necesitamos aquí, ya que el asterisco (*
) iría al final de la línea en este escenario. La barra diagonal (/
) completa la sección de patrones de búsqueda./2,/1 /g'
: Debido a que encerramos nuestras dos subexpresiones entre paréntesis, podemos referirnos a ambas por sus números. Debido a que queremos invertir el orden, los escribimos comosecond-match,first-match
. Los números deben ir precedidos de una barra diagonal inversa (/
)./g
: Esto permite que nuestro comando trabaje globalmente en cada línea.geeks.txt
: El archivo en el que estamos trabajando.
También puede utilizar el comando Cortar (c
) para sustituir líneas enteras que coincidan con su patrón de búsqueda. Escribimos lo siguiente para buscar una línea con la palabra “cuello” en ella, y reemplazarla con una nueva cadena de texto:
sed '/neck/c Around my wrist was strung' coleridge.txt
Nuestra nueva línea aparece ahora en la parte inferior de nuestro extracto.
Inserción de líneas y texto
También podemos insertar nuevas líneas y texto en nuestro archivo. Para insertar nuevas líneas después de las coincidentes, usaremos el comando Append (a
).
Aquí está el archivo con el que vamos a trabajar:
frikis de los gatos.txt
Hemos numerado las líneas para que esto sea un poco más fácil de seguir.
Escribimos lo siguiente para buscar líneas que contengan la palabra “Él” e insertamos una nueva línea debajo de ellas:
sed '/He/a --> Inserted!' geeks.txt
Escribimos lo siguiente e incluimos el comando Insertar (i
) para insertar la nueva línea encima de las que contienen texto coincidente:
sed '/He/i --> Inserted!' geeks.txt
Podemos usar el ampersand (&
), que representa el texto coincidente original, para agregar texto nuevo a una línea coincidente. /1
, /2
, y así sucesivamente, representan subexpresiones coincidentes.
Para agregar texto al comienzo de una línea, usaremos un comando de sustitución que coincida con todo lo que hay en la línea, combinado con una cláusula de reemplazo que combina nuestro nuevo texto con la línea original.
Para hacer todo esto, escribimos lo siguiente:
sed 's/.*/--> Inserted &/' geeks.txt
Escribimos lo siguiente, incluyendo el G
, que agregará una línea en blanco entre cada línea:
sed 'G' geeks.txt
Si desea agregar dos o más líneas en blanco, puede usar G;G
, G;G;G
, y así sucesivamente.
Eliminación de líneas
El comando Eliminar (d
) elimina las líneas que coinciden con un patrón de búsqueda, o las especificadas con números de línea o rangos.
Por ejemplo, para eliminar la tercera línea, escribiríamos lo siguiente:
sed '3d' geeks.txt
Para eliminar el rango de líneas de cuatro a cinco, escribiríamos lo siguiente:
sed '4,5d' geeks.txt
Para eliminar líneas fuera de un rango, utilizamos un signo de exclamación (!
), como se muestra a continuación:
sed '6,7!d' geeks.txt
Guardar los cambios
Hasta ahora, todos nuestros resultados se han impreso en la ventana del terminal, pero aún no los hemos guardado en ninguna parte. Para que estos sean permanentes, puede escribir los cambios en el archivo original o redirigirlos a uno nuevo.
Sobrescribir el archivo original requiere cierta precaución. Si su sed
es incorrecto, puede realizar algunos cambios en el archivo original que son difíciles de deshacer.
Para un poco de tranquilidad, sed
puede crear una copia de seguridad del archivo original antes de que ejecute su comando.
Puede utilizar la opción In-place (-i
) para decir sed
para escribir los cambios en el archivo original, pero si le agrega una extensión de archivo, sed
hará una copia de copia de 200 del archivo original en uno nuevo. Tendrá el mismo nombre que el archivo original, pero con una nueva extensión de archivo.
Para demostrarlo, buscaremos cualquier línea que contenga la palabra “Él” y las eliminaremos. También haremos una copia de respaldo de nuestro archivo original en uno nuevo usando la extensión BAK.
Para hacer todo esto, escribimos lo siguiente:
sed -i'.bak' '/^.*He.*€/d' geeks.txt
Escribimos lo siguiente para asegurarnos de que nuestro archivo de copia de seguridad no haya cambiado:
cat geeks.txt.bak
También podemos escribir lo siguiente para redirigir la salida a un nuevo archivo y lograr un resultado similar:
sed -i'.bak' '/^.*He.*€/d' geeks.txt > new_geeks.txt
Utilizamos cat
para confirmar que los cambios se escribieron en el nuevo archivo, como se muestra a continuación:
cat new_geeks.txt
Haber sembrado todo eso
Como probablemente hayas notado, incluso esta introducción rápida en sed
es bastante largo. Hay mucho en este comando, e incluso hay más puedes hacer con él.
Con suerte, sin embargo, estos conceptos básicos han proporcionado una base sólida sobre la cual puede construir a medida que continúa aprendiendo más.