¿Cómo uso el comando sed en Texto-plano?

Puede sonar extraño, pero el comando sed es realmente un editor de texto
sin interfaz alguna. Puedes usarlo desde tu intérprete de comandos en
texto-plano.xyz para manupular texto tanto en ficheros como con cadenas.
¡Con este tutorial aprenderás a dominar su inusitado poder! El Poder de
sed

El coamdno sed se asemeja al ajedrez: lleva una ahora aprenderlo, y una
vida dominarlo (o, al menos, mucha práctica). Aprenderás una apertura o
gambito en cada categoría principal en tu manejo de la funcionalidad de
sed.

sed es un editor de cadenas que opera con una entrada en caños o
ficheros de texto. Sin embargo, acrece de una interfaz interactiva de un
editor de texto. En lugar de ella, deberás proveer las instrucciones
para que él siga en la medida que avanza sobre el texto. Esto también
funciona en Bash y otros intépretes de línea de comandos.

Con sed, puedrás:

    Seleccionar texto 
    Sustituír texto 
    Agregar líneas al texto 
    Borrar líneas de un texto 
    Modificar (o preservar) un fichero original

Se han estructurado estos ejemplos para presentar y demostrar conceptos,
y no para producir los comandos de sed más rígido (y más complejos)
posibles. Incluso así, verás que en sed las funcionalidades de
coincidencia de cadenas y selección de texto operan a través del uso de
expresiones regulares (regexes). Deberías familiarizarte con ellas para
obtener lo mejor de sed. Un Ejemplo Simple

Primero vamos a usar echo para enviar algún texto a sed a través de un
caño, y haremos que sed sustituya una porción del texto. Para hacerlo,
ingresamos:

echo howtogonk | sed 's/gonk/geek/'

El comando echo envía la cadena “howtogonk” a sed, y aplica nuestra
regla simple de sustitución (la "s" signfifica sustituir). sed buscará
la cadena de texto en el texto contenido en el fichero, y reemplazará
cualquier coincidencia con la segunda.

La cadena “gonk” será reemplazada por “geek”, y la nueva cadena será
presentada en la terminal.

Si bien las sustituciones son probablemnete el empleo mas común que se
hace de sed, es conveniente saber cómo seleccionar y hacer coincidir
texto. Seleccionar Texto

Utiliza un fichero de texto para nuestro ejemplo. Usa uno que contiene
una selección de versos del poema épocio de Samuel taylor Coleridge "The
Rime of the Ancient Mariner".

Ingresamos lo siguiente para mirarlo con el comando less:

less coleridge.txt

Para seleccionar algunas líneas del finchero, proveemos la línea inicial
y la línea final del rango de lección. Si usamos un número aislado, sólo
seleccionaremos dicha línea.

Para extraer las líneas uno a la cuatro, ingresa este comando:

sed -n '1,4p' coleridge.txt

Observa la coma entre 1 y 4. La p significa "presenta las líneas
coincidentes". Por defecto, sed presentará todas las líneas. Veríamos
todo el texto en el fichero, y las líneas coincidentes resultarían
impresas dos veces. Para impedirlo, emplea la opción -n (sin salida)
para suprimir todo el texto no coincidente.

Cambiamos los números de línea de modo que podamos seleccionar un verso
diferente, como se indica:

sed -n '6,9p' coleridge.txt

Puedes usar la opción -e ("expresión") para realizar selecciones
múltiples. Si usas dos expresiones, podrás seleccionar dos versos, tal
como:

sed -n -e '1,4p' -e '31,34p' coleridge.txt

Si reduces el primer número en la segunda expresión, podrás insertar una
línea en blanco entre los dos versos. Tipea lo siguiente:

sed -n -e '1,4p' -e '30,34p' coleridge.txt

También puedes escoger una línea de comienzo e indicarle a sed que
avance a lo largo del fichero e imprima las líneas alternadamente, cada
cinco líneas, o que saltee un número dado de líneas. El comando es
similar a aquelos que empleamos anteriormente para seleccionar un rango.
Esta vez, sin embargo, usarás un tilde (~) en lugar de una coma para
separa los números.

El primer número indica el comienzo de la línea. El segundo número le
indica a sed qué líneas luego de la línea de comienzo deseas ver. El
número 2 significa cada segunda línea, 3 significa cada tercer línea, y
así.

Ingresa lo siguiente:

sed -n '1~2p' coleridge.txt

Normalmente no se sabe dónde se localiza exactamente un texto buscado,
lo que implica que suele ser imposible proveer los números de línea. Sin
embargo, podrás usar sed para seleccionar las líneas que contienen la
cadena de texto que buscas. Por ejemplo, extrae todas las líneas que
comienzan con "And".

El caret (^) representa el comienzo de una línea. Delimintaremos nuestro
término a buscar en barras (/). También incluirás un espacio luego de
"And", de manera tal que las palabras como "Androide" no aparecerán en
el resultado.

Al leer por primera ver guiones que incluyen sed, puede parecer poco
obvio. Recordemos que en los comandos anteriores expliqué que /p
significa "presentar", o bien "imprimir". Sin embargo, ahora una barra
la antecede, de esta manera:

sed -n '/^And /p' coleridge.txt

Tres líneas que comienzan con "And" serán extraídas del fichero y
presentadas en la terminal.


	Realizar Sustiticiones

En nuestro primer ejemplo, expuse el primer formato básico para usar la
substitución en sed:

echo howtogonk | sed 's/gonk/geek/'

La s indica a sed que lo que viene a continuación es una sustitución
lineal. La primera cadena consistirá en la cadena a buscar, mientras que
la segunda cadena será el contenido quiere reemplazar. Por supuesto,
como sucede en BSD, el demonio está en los detalles.

Ingresa entonces el siguiente comando para cambiar todas las apariciones
de la cadena "day" a "week", y le daremos al marinero y al albatros más
tiempo para sentirse unidos:

sed -n 's/day/week/p' coleridge.txt

En la primer línea, sólo se cambiará la segunda ocurrencia de "day". Eso
es así porque sed se detiene luego del la primer coincidencia por cada
línea. Si queremos realizar una búsqueda global - tal que se procesen
todas las coincidencias existentes en cada línea del fichero, debemos
agregar un modificador g, de la siguiente manera:

sed -n 's/day/week/gp' coleridge.txt

Esto encontrará tres de cuatro en la primera línea. Porque la primera
palabra es "Day," y sed es sensible a las mayúsculas, y no considera que
dicha instancia sea lo mismo que "day".

Para solucionar esto, ingresaremos el siguiente comando, agregándole una
i al final de la expresión que indicque insensibilidad a mayúsculas:

sed -n 's/day/week/gip' coleridge.txt

Esto funcionará, pero la mayoría de las veces no querrás activar la
insensibilidad a mayúsculas para todo. En tales casos, podrías usar un
grupo de expresión regular que agregue insensibilidad de mayúsculas a
cadenas específicas.

Por ejemplo, si encierras los caracteres entre corchetes ([]), serán
interpretados como "cualquier caracter de esta lista de caracteres".

Introduce lo siguiente para incluir "D" y "d" en el grupo, de forma de
asegurar que en la coincidencia entren tanto "Day" como "day":

sed -n 's/[Dd]ay/week/gp' coleridge.txt

También podrás restringir la sustituciones a determinadas secciones del
fichero. Supongamos que el fichero contiene un espaciado erróneo en el
primer vereso. Podrás usar entonces el siguiente comando ya conocido
para analizar el primer verso:

sed -n '1,4p' coleridge.txt

Busca ahora dos espacios y sustitúyelos por uno. Harás esto globalmente
de manera que la acción se repita a lo largo de toda la primer línea.
Para ser mas claro, la cadena de búsqueda es "espacio, espacio asterisco
(*)", y la cadena de sustitución es "espacio". El 1,4 restringe la
sustitución a únicamente las primeras cuatro líneas del fichero.

Todo esto tendrá la forma del siguiente comando:

sed -n '1,4 s/ */ /gp' coleridge.txt

¡Excelente! Lo que importa aquí es el patrón de búsqueda. El asterisco
(*) representa cero o más del caracter precedente, que es un espacio.
por ello, el patrón a buscar analiza cadenas de un espacio o más.

Si sustituyes un espacio simple por cualquier secuencia múltiple de
espacios, corregirás el fichero a un espaciado regular, con un espacio
simple entre cada palabra. En realidad, esto también sustituirá el uso
de espacios simples por otro espacio simple igual, y aunque no es
adverso en el resultado, enlentecerá la sustitución.

Si tipeas lo siguiente y reduces el patrón de búsqueda a un espacio
simple, vereás inmediatamente porqué se hace necesario incluir los dos
espacios:

sed -n '1,4 s/ */ /gp' coleridge.txt

Como el asterisco busca cero o más del caracter precedente, interpretará
cada caracter que no sea un espacio como un "cero espacio" y le aplicará
la sustitución.

Sin embargo, si incluyes dos espacios en la cadena de búsqueda, sed
deberá encontrar al menos un caracter de espacio antes de aplicar la
substitución. Esto asegurará que los caracteres que no son espacioes
permanezca inalterados.

Si ingresas lo siguiente, usando la -e (expresión) que ya has utilizado
anteriormente, te permitirá ahora realizar dos o más sustituciones en
simultáneo:

sed -n -e 's/motion/flutter/gip' -e 's/ocean/gutter/gip' coleridge.txt

Podrás lograr el mismo resultado utilizando un punto y coma (;) para
separar ambas expresiones, de la siguiente manera:

sed -n 's/motion/flutter/gip;s/ocean/gutter/gip' coleridge.txt

Cuando sustituímos "day" por "week" en el siguiente comando, la
instancia de "day" en la expresión "well a-day" también fue cambiada:

sed -n 's/[Dd]ay/week/gp' coleridge.txt

Para impedir esto, deberás sólo intentar sustituir en líneas que
coincidan con otro patrón. Si modificas el comando para tener una cadena
de búsqueda al comienzo, sólo consideraremos operar en líneas que
coincidan con dicha cadena.

Ingresa lo siguiente para hacer que tu patrón de búsqueda sea la palabra
"after".

sed -n '/after/ s/[Dd]ay/week/gp' coleridge.txt

Esto te dará el resultado buscado.


	Sustituciones más complejas

Démosle un descanso a Coleridge y usemos ahora sed para extraer nombres
del fichero /etc/passwd.

Hay maneras más cortas de hacerlo (que se expondrán luego), pero usemos
la forma más compleja para demostrar otro concepto. Cada ítem
coincidente en un patrón de búsqueda (llamadas subexpresiones) puede
recibir numeraciones (hasta un máximo de nueve ítems). Podrás utilizar
dichos números en tus comandos de sed para referenciar subexpresiones
específicas.

Debes cerrar las subexpresiones entre paréntesis precedidas con una
barra invertida (\) para que esto funcione. De lo contrario las
subexpresiones serían interpretadas como un caracter normal.

Para hacerlo, tipearás lo siguiente:

sed 's/\([^:]*\).*/\1/' /etc/passwd

Desglosemos esto:

    sed 's/: El comando sed y el comienzo de la expresión de
    sustitución. \(: El paréntesis abierto [(] precedido por una barra
    invertida(\) abre una subexpresión.

    [^:]*: La primer subexpresión de la cadena de búsqueda contiene un
    grupo en corchetes. Cuando se lo usa en un grupo, el caret (^)
    significa “no”. Un grupo significa que cualquier caracter que no sea
    dos puntos (:) será aceptado como una coincidencia.

    \): El paréntesis cerrado [)] precedido por una barra invertida (\).

    .*: Esta segunda subexpresión de búsqueda significa "cualquier
    caracter y cualquier cantidad de ellos".

    /\1: La porción de sustitución de la expresión contiene 1 precedido
    por una barra invertida (\). Esto representa el texto que coincide
    con la primera subexpresión.

    /': La barra (/) y el apóstrofe (') terminan el comando de sed.

Lo que todo esto significa es que se buscará cualquier cadena de
caracteres que no contienen un caracter de dos puntos (:), las cuales
serán la primer instancia de un texto coincidente. Luego, se buscará
cualquier cosa en dicha línea, la cual será la segunda instancia del
texto coincidente. Se sustituirá la línea entera con el texto que está
indicado en la primer subexpresión.

Cada línea del fichero /etc/passwd contiene con un nombre de usuario
terminado por un caracter de dos puntos, y luego se sustituirá dicho
valor por la línea entera. De esta forma, habremos aislados los nombre
de usuario. Salida desde

A continuación, cerraremos la segunda subexpresión entre paréntesis
("()"), de modo de poder referenciarla por un número también. También
reemplazarás \1 con \2. El comando ahora sustituirá la línea entera con
todo a partir del primer caracter de dos puntos (:), hasta el final de
la línea.

Para ello ingresa:

sed 's/\([^:]*\)\(.*\)/\2/' /etc/passwd

Estos cambios pequeños dan por invertir el significado de todo el
comando, por lo cual recibiremos todo excepto los nombres de usuarios.

Ahora, hechemos un vistazo a una forma rápida y simple de hacer lo
mismo:

Nuestro término de busqueda opera a partir del primer caracter de dos
puntos (:) hasta el final de la línea. Como nuestra expresión de
sustutución está vacía ("//"), no reemplazará el texto coincidente con
cadena alguna.

De modo que si tipeamos lo siguiente, quitando todo desde el primer
caracter de dos puntos (:) hasta el final de la línea, se logrará el
efecto anterior de dejar sólo los nombres de usuario:

sed 's/:.*//" /etc/passwd

Ahora miremos un ejemplo en el cual referenciamos la primer y segunda
coincidencia el mismo comando.

Tenemos un fichero donde comas (,) separan el nombre y el apellido.
Deseamos listarlos como "apellido, nombre". Podremos usar cat, como se
muestra abajo, para ver qué hay en este fichero:

cat geeks.txt

Como casi todos los comandos de sed, este podría en principio parecer
inabarcable:

sed 's/^\(.*\),\(.*\)$/\2,\1 /g' geeks.txt

Se trata de un comando de sustitución como los anteriores, y la cadena
de búsqueda es bastante simple. Desglosémoslo:

    sed 's/: El comando de sustitución normal.

    ^: Como el caret no está en un grupo ([]), se interpreta como "el
    comienzo de la línea".

    \(.*\),: La primera subexpresiñon es cualquier cantidad de cualquier
    caracter. Está entre paŕentesis "()", cada una de las cuales está
    precedida por una barra invertida "\", de modo que se referenciará
    por un número. El comando se interpretará como "buscar desde el
    comienzo de la línea hasta la primer coma "," cualquier cantidad de
    cualquier caracter."

    \(.*\): La siguiente subexpresión es -nuevamente- cualquier cantidad
    de cualquier caracter. También está entre paréntesis, "()" ambos de
    los cuales se hayan precedidos por una barra invertida "\", de modo
    que podemos referenciar nuevamente el texto coincidente por número.

    $/: El signo peso ($) representa el fin de la línea y permitirá a
    nuestra búsqueda continuar hasta el final de la línea. Se usa esto
    simplemente para presentar aquí el signo peso. Realmente no se
    necesita, ya que el asterisco (*) haría llegar hasta el final de la
    lónea en este escenario. La barra (/) completa la búsqueda de la
    cadena.

    \2,\1 /g': Como cerramos nuestras dos subexpresiones entre
    paréntesis, podemos referir a ambas por sus números. Ya que deseamos
    invertir su órden, las ingresamos como
    segunda-coincidencia,primera-coincidencia. Los números deben ser
    precedidos por una barra invertida (\).

    /g: Esto activa la operación global en cada línea. geeks.txt: El
    fichero en el que estamos trabajando.

También puedes usar el comando Cortar (c) para sustituir líneas entera
que coincidan con la cadena de búsqueda propuesta. Tipearemos lo
siguiente para buscar una línea con la palabra "neck" en ella, y la
reemplazaremos con una nueva cadena de texto:

sed '/neck/c Around my wrist was strung' coleridge.txt

Nuestra nueva línea aparecerá en la parte inferior de nuestro extracto.


	Insertar Líneas y Texto

También podremos insertar nuevas líneas y texto en nuestro fichero. Para
insertar líneas nuevas a continuación de cualquieras que coincidan,
usaremos el comando Agregar (a).

He aquí el fichero con el que queremos trabajar:

cat geeks.txt

Hemos numerados las líneas para hacerlo más simple de entender.

Tipea el siguiente comando para buscar líneas que contengan la palabra
"He," e inserta una nueva línea debajo de ellas:

sed '/He/a --> Inserted!' geeks.txt

Tipea lo siguiente e incluye el comando Insertar (i) para insertar la
nueva línea por encima de aquellas que contienen el texto coincidente:

sed '/He/i --> Inserted!' geeks.txt

Podemos usar el caracter et o ampersand ("&"), que representa al texto
coincidente original, para agregar una cadena de texto nuevo a la línea
coincidente. \1 , \2 y demás, representan las subexpresiones
coincidentes.

Oara agregar texto al comienzo de una línea, se utiliza un comando de
sustitución que haga coincidir todo en la línea, combinado con una
cláusula de reemplazo que combine nuestro nuevo texto con la línea
original.

Para hacerlo, introduce lo siguiente

sed 's/.*/--> Inserted &/' geeks.txt

Tipea lo siguiente, incluyendo el comando G, que agregará una línea en
blanco entre cada línea:

sed 'G' geeks.txt

Si deseas agregar dos, o tres líneas en blanco, puedes usar G;G, G,G,G,
y así. Borrar líneas

El comando Borrar (d) borra las líneas que coincidan con el patrón de
búsqueda, o aquellas líneas especificadas números de líneas o rangos de
líneas.

Por ejemplo, para borrar la tercer línea, tipearíamos lo siguiente:

sed '3d' geeks.txt

Para borrar el rango de línas cuatro a cinco, tipearíamos lo siguiente:

sed '4,5d' geeks.txt

Para borrar las líneas por fuera de un rango dado, usaríamos un signo de
exclamación, de la siguiente manera:

sed '6,7!d' geeks.txt 


	Guardar los Cambios

Hasta ahora, todos los resultados se han presentado en la terminal, pero
no los hemos guardado en ningún lado. Para hacerlos permanente, o bien
se pueden guardar los cambios en el fichero original, o redirigir la
salida a un fichero nuevo.

Sobreescribir el fichero original puede parecer lo obvio a realizar,
pero suele requerir cierto cuidado. Si el comando ingresado con sed es
incorrecto, podrías realizar cambios al fichero original que fuesen muy
difíciles de revertir.

Es una buena política instruir a sed para que cree una copia de respaldo
del fichero original antes de ejecutar cualquier comando.

Puedes usar la opción En el Lugar (-i) para indicar a sed que escriba
los cambios al fichero original, pero si le agregas una extensión de
archivo, sed procederá a respaldar el fichero original con dicha
extensión. Tendrá el mismo nombre que el fichero original, pero con una
nueva extensión.

Para demostrarlo, busca cualquier línea que contiene la palabra "He" y
bórrala. También respaldaremos nuestro fichero original a uno nuevo
aplicándole la extensión .BAK.

Para hacerlo así, ingresa lo siguiente:

sed -i'.bak' '/^.*He.*$/d' geeks.txt

Tipea lo siguiente para asegurarte que tu fichero de respaldo no
presenta cambio alguno.

cat geeks.txt.bak

También puedes tipear el siguiente comando para redirigir la salida a un
fichero nuevo y lograr un resultado similar:

sed -i'.bak' '/^.*He.*$/d' geeks.txt > new_geeks.txt

Utiliza cat para confirmar que los cambios han sido realizados y
escritos en un fichero nuevo, como se indica a continuación:

cat new_geeks.txt


	Habiendo dicho Todo esto

Como has notado, incluso este pequeño apunte de sed es bastante extenso.
Existen muchas posibilidades para este comando, y existen muchísimas
cosas que puedes realizar con él.

Con suerte, estos conceptos básicos te habrán provisto de un cimiento
sólido sobre el que puedas continuar aprendiendo. ¡Sacía tu sed de sed!