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

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

  1. Sustitución de texto: La opción más común de sed es la sustitución de texto, que se realiza utilizando el comando s.

    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
    
  2. 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
    
  3. 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
    
  4. 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

  1. Reemplazar todas las apariciones de “cat” con “dog” en un archivo:

    sed -i 's/cat/dog/g' archivo.txt
    
  2. Eliminar todas las líneas vacías en un archivo:

    sed '/^$/d' archivo.txt
    
  3. 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
    
  4. 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.