Redirecciones y pipelines
I/O Redirections
Antes que nada : I de input , O de output.
Cuando nosotros ejecutamos un comando como el ls
vemos el resultado por la terminal
seria la salida, un output.
Normalmente las utilidades que tenemos en la shell de linux nos devuelven dos tipos de informacion.
Por un lado es la propia informacion que nos devuelve un programa.
Por otro, mensajes de estado y de error que nos indica si el programa se ejecuto correctamente.
Por ejemplo si hacemos ls 3423423423
obtendremos un mensaje de estado:
ls je8ifdjeife
ls: cannot access 'je8ifdjeife': No such file or directory
Como es que estos programs logran imprimir por pantalla estos tipos de informacion?
Lo que hacen, es escribirlo primero en un fichero especial que se llama, standard output o stdout.
Si vamos a /dev/stdout
y vemos sus propiedades:
ls -la /dev/stdout
lrwxrwxrwx 1 root root 15 May 13 11:07 /dev/stdout -> /proc/self/fd/1
Vemos que es un enlace simbolico hacia /proc/self/fd/1
Si seguimos esa ruta, para ver que detalles nos puede dar, vemos:
ls -la /proc/self/fd/1
lrwx------ 1 akerman akerman 64 May 16 11:24 /proc/self/fd/1 -> /dev/pts/0
Vemos que es otro eslance simbolico hacia dev/pts/0
Si Seguimos una vez mas profundizando sobre este fichero:
ls -la /dev/pts/0
crw--w---- 1 akerman tty 136, 0 May 16 11:25 /dev/pts/0
Este es un fichero especial, que esta referenciado con una C : crw—w---- esta C quiere decir que es un character device file es un tipo de fichero especial que sirve de interfaz, en este caso con la terminal.
Esto quiere decir , que recibe ciertos caracteres, como los que le pasa ls
y va
a mostrarla por pantalla.
Ya con esto explicado sabemos que :
Al usar un comando como lo es ls
este program enviara el texto obtenido
a un archivo especial llamado stdout
y este hace de interfaz para
mostrarlos en pantalla.
Como comentabamos antes, hay otros tipos de mensajes, como los
de status y error, estos no van hacia stdout
sino que van a otro
fichero mas precisamente a /dev/stderr. Pero en el fondo
este tambien termina apuntando a dev/pts/0.
Tenemos ciertos comandos que nop piden que ingresemos texto utilizando el teclado, este tipo de entrada se lo denomina standard input, el cual tiene un fichero especial asociado en /dev/stdin. tambien apunta a dev/pts/0.
Redirecciones
Ahora vamos a ver como redirigir esas salidas a un lugar que nos interese.
Para eso nos vamos a apoyar de el caracter especial >
este es el caracter
de redireccion.
ls -lah > salida_ls.txt
Asi se nos creara automaticamente un archivo con el resultado.
Que pasaria si intentamos con un directorio q no existe:
ls -lah sdfuhwuehf > salida_ls.txt
ls: cannot access 'euifhuwehufhwe': No such file or directory
Si intentamos leer el archivo de cat salida_ls.txt
veremos que esta vacio
Esto es asi porque al ser un error, la salida es de tipo strerr y
el operador especial >
funciona con salidas de tipo strout.
Porque esta vacio? el operador >
lo que hace es reescribir desde el principio
el archivo, como en este caso no hubo salida mediante _strout lo dejo en blanco.
Podemos usar esta caracteristica a nuestro favor, si queremos crear un fichero nuevo vacio
usamos > nuevofichero.txt
en vez de hacer el tipico touch nuevofichero.txt
Como logro concatenar resultados para evitar que se borre el output anterior?
Usamos >>
seria : echo "nueva linea" >> salida.txt
>
solo funciona para salidas stdout>>
para concatenar al final del fichero de destino
Si todos los standard outpus apuntan al mismo sitio, que es lo que diferenecia su comportamiento?
El que se encarga de eso es el file descriptor, el stdout tiene un file descriptor(fd) asociado, el strerr otro y el stdin. Que apuntan a una entrada en la global file table donde tienen seteado las restricciones de acceso y que indica que uno sirve para redireccionar errores, otro capturar entradas en el taclado y otro para redireccion de outputs.
Redirigir stderr
Para estos casos, no tenemos un operador que nos permita directamente redirigir este tipo de mensajes.
Primero nos interesa saber cual es el file descriptor de un fichero.
ls -l /dev/stdout
lrwxrwxrwx 1 root root 15 May 13 11:07 /dev/stdout -> /proc/self/fd/1
Si vemos el fd es el 1.
Si lo hacemos para el /dev/stderr
es el 2
Como usar el file descriptor para redireccionar stderr
ls -l fhuwehufiwei 2> error_ls.txt
Podriamos usar el fd explicitamente para el stdout con 1>
pero no hace falta
Redirigir en simultaneo stderr y stdout
La manera con retrocompatibilida es la siguiente:
ls -lah > ls-salida.txt 2>&1
Con &1
estamos diciendo que redirija los errores al argumento ls-salida
La manera mas moderna, es esta:
ls -lah &> salida.txt
Para concatenar &>>
/dev/null
Lo interesante de este fichero aparte de de que es un caracter device file es que todo lo que redirijamos ahi,se va a eliminar, es como si fuera una papelera.
Para que nos sirve?
Por ejemplo si haciamos find /var/log -name auth.log
veiamos lo siguiente:
/var/log/auth.log
find: ‘/var/log/private’: Permission denied
find: ‘/var/log/samba/cores’: Permission denied
find: ‘/var/log/sssd’: Permission denied
find: ‘/var/log/gdm3’: Permission denied
find: ‘/var/log/speech-dispatcher’: Permission denied
Y para omitir la salida de los errores hacemos esto :
find /var/log -name auth.log 2> /dev/null
/var/log/auth.log
Asi omitiremos los errores y no lo guardamos en ningun lado.
Stdin
Podemos usa el operado <
para volcar el contendio de un fichero a un comando, un ejemplo
trivial seria con cat
podemos hacer cat < fichero-con-texto.txt
y la salida seria el
contenido, esto no tiene mucho sentido con cat
ya que cat fichero-con-texto.txt
nos
daria el mismo resultado.
Pero en otros contextos nos ahorraria tener que escribir mucha informacion.
Como dato adicional si hacemos
cat
sin argumentos, quedara a la espera de que pongamos algo, automaticamente ira al stdout y lo veremos por pantalla. tene en cuenta que para que funcione, el programa tiene que esperar un stdin como argumento.
Pipeline
Nos permite es concatenar comandos dentro de la shell de manera que el stdout de un comando
sirva de stdin de otro. |
ls -l /usr/bin | less
Filtros y busquedas
El primer comando es sort
nor sirve para ordenar
las lieneas de un fichero de texto y en base a
diferentes criterios, por default lo hara de orden alfabetico.
Podemos combinar esto con pipelines, por ejemplo si listamos /bin
y /usr/bin
veremos que tenemos un
monton de archivo. Podemos hacer ls /bin /usrl/bin | sort | less
para ir pasando como argumentos los
resultados de los comandos anteriores.El resultado sera algo asi :
[
[
411toppm
411toppm
aa-enabled
aa-enabled
aa-exec
aa-exec
aa-features-abi
aa-features-abi
aconnect
aconnect
acorn
acorn
add-apt-repository
add-apt-repository
addpart
addpart
addr2line
addr2line
airscan-discover
airscan-discover
Vemos que ademas de estar odenados alfabeticamente, estan duplicados, ya que /bin y usr/bin son la misma carpeta, mas precisamente uno es un enlace simbolico.
Para omitir los repetidos podemos usar uniq
y quedaria asi :
ls /bin /usr/bin | sort | uniq | less
[
411toppm
aa-enabled
aa-exec
aa-features-abi
aconnect
acorn
add-apt-repository
addpart
addr2line
airscan-discover
Si queremos ver solo los duplicados usariamos uniq -d
Conociendo datos de ficheros con wc
wc
nos permite saber el numero de lineas, la cantidad de palabras y los bytes de un fichero.
wc /var/log/auth.log
690 7058 90121 /var/log/auth.log
En este caso 960 son las lineas , 7058 son las palabras y 90121 son los bits.
Con -l
solo nos devolveria el numero de lineas (690)
Si queremos saber la cantidad de ficheros de un directorio usariamos wc (world count) junto a pipelines asi :
ls /bin /usr/bin/ | sort | uniq | wc -l
1372
Mas comandos
Grep
Recibe un fichero y nos devuelve las lineas que hagan match con un patron que nosotros le indiquemos
grep akerman /var/log/auth.log
Para que no tenga en consideracion las mayusculas y las minusculas , usamos -i
: grep -i akerman /var/log/auth.log
Para que nos devuelva todas las que no coinciden usarmos -v
Adicionalmente podemos usar wildcards grep akerman* /var/log/auth.log
head
Por defecto nos muestra las primeras 10 lineas de un fichero.
head /var/log/auth.log
tail
Hace lo mismo pero muestra las 10 ultimas lineas.
Para especificar la cantidad de linas que queremos hacemos : head -n 5
Con pipelines : ls /usr/bin | tail -n 15
tail en tiempo real.
Hacemos uso de -f : tail -f
:
tail -f /var/log/auth.log
Debugging con tee
Si vamos concatenando muchos comandos con con el pipeline , puede que en medio haya un error, entonces, como sabemos donde se produjo?
Podemos usar tee
asi :
ls /usr/bin | sort | tee fichero_sort.txt | uniq | grep cat
En ese caso la salida de sort
la va a volcar en fichero_sort.txt pero al mismo tiempo
la envia al standard output, por lo cual le llega a uniq
sed
SED, que significa “stream editor” (editor de flujo), es una herramienta de línea de comandos en Unix y Linux utilizada para realizar operaciones básicas de edición de texto en un flujo de datos. Es especialmente útil para procesar y transformar texto de manera automatizada y eficiente. Puedes usar sed
para buscar, reemplazar, insertar y eliminar texto.
Principales usos de sed
-
Sustitución de texto: La opción más común de
sed
es la sustitución de texto, que se realiza utilizando el comandos
.Sintaxis básica:
sed 's/patrón/reemplazo/' archivo
Ejemplo: Para reemplazar la primera aparición de “foo” por “bar” en cada línea de un archivo:
sed 's/foo/bar/' archivo.txt
Para reemplazar todas las apariciones de “foo” por “bar” en cada línea:
sed 's/foo/bar/g' archivo.txt
-
Edición en el lugar: Puedes editar el archivo original en lugar de simplemente mostrar la salida modificada.
Sintaxis:
sed -i 's/patrón/reemplazo/' archivo
Ejemplo: Para reemplazar “foo” por “bar” en el archivo
archivo.txt
directamente:sed -i 's/foo/bar/g' archivo.txt
-
Eliminar líneas: Puedes eliminar líneas específicas.
Sintaxis:
sed 'número_d_línea d' archivo
Ejemplo: Para eliminar la tercera línea de un archivo:
sed '3d' archivo.txt
Para eliminar todas las líneas que contienen una palabra específica:
sed '/palabra/d' archivo.txt
-
Insertar y añadir texto: Puedes insertar texto antes o después de una línea específica.
Sintaxis:
sed 'número_d_línea i\texto' archivo # insertar antes de la línea sed 'número_d_línea a\texto' archivo # añadir después de la línea
Ejemplo: Para insertar “Nuevo texto” antes de la tercera línea:
sed '3i\Nuevo texto' archivo.txt
Para añadir “Nuevo texto” después de la tercera línea:
sed '3a\Nuevo texto' archivo.txt
Ejemplos prácticos
-
Reemplazar todas las apariciones de “cat” con “dog” en un archivo:
sed -i 's/cat/dog/g' archivo.txt
-
Eliminar todas las líneas vacías en un archivo:
sed '/^$/d' archivo.txt
-
Añadir una línea de texto después de cada línea que contiene una palabra específica:
sed '/palabra/a\Texto añadido' archivo.txt
-
Cambiar el delimitador de campos en un archivo CSV: Si tienes un archivo CSV separado por comas y quieres cambiarlo a separado por punto y coma:
sed 's/,/;/g' archivo.csv
Conclusión
sed
es una herramienta poderosa y versátil para la edición de texto en flujos de datos en Unix y Linux. Con la práctica, se convierte en una herramienta indispensable para tareas de procesamiento de texto y scripts de automatización. Para profundizar más en sed
, puedes consultar su manual oficial.