Uno de los pilares de Linux es que es un sistema compuesto por pequeñas utilizadades que hacen una cosa, pero la hacen extremadamente bien.
Podemos combinar la salida de un comando y enviarla, como input, a otro comando usando la pipe
(|
).
Por ejemplo, podemos usar cat $filename | grep 'hello'
para filtrar el contenido del fichero $filename
y quedarnos únicamente con las líneas que contengan hello
.
¿Cómo podemos conseguir lo mismo en nuestras scripts en Bash?
Imagina que necesitas una función como to_lowercase
, que convierte a minúsculas un texto. La función podría ser algo como:
to_lowercase() {
local input_string
input_string="$1"
echo "${input_string,,}"
}
Ahora, en un script en el que esté disponible está función to_lowercase
, podemos usarla de la siguiente manera:
#!/usr/bin/env bash
source to_lowercase.sh
to_lowercase "My MIXed UPPERcase TEXT"
Puedes llamar a la función en el script como to_lowercase "My MIXed UPPERcase TEXT"
y el resultado es el esperado my mixed uppercase text
.
¿Pero qué pasa si intantas hacer algo como echo "My MIXed UPPERcase TEXT" | to_lowercase
?
No obtenemos nada a la salida. La explicación es que to_lowercase
espera un parámetro, pero no le pasamos ninguno, de manera que input_string
está vacío (y eso es lo que muestra el comando echo
).
Aceptando input desde stdin
Transformar la función en nuestro script para que se comporte como esperamos, aceptando como entrada la salida de otro comando o función de nuestro script, es realmente sencillo.
to_lowercase() {
local input_string
input_string="$1"
if [[ "$input_string" == "" ]]; then
read -r input_string
fi
echo "${input_string,,}"
}
Ahora la ejecución de echo "My MIXed UPPERcase TEXT" | to_lowercase
en nuestro script:
#!/usr/bin/bash
source to_lowercase
echo "My MIXed UPPERcase TEXT" | to_lowercase
proporciona el resultado esperado.
Como puede verse, la modificación que hemos hecho en la función es usar read
para leer input desde stdin
; pero en este caso, en vez de que sea el usuario el que proporcione el texto, el comando read
lo lee desde la salida del comando anterior, a través de la pipe |
, ya que ahí es donde escribe el comando echo
.
Encdenando múltiples funciones
Si incorporamos el mecanismo de leer desde stdin
en todas nuestras funciones, podemos encadenarlas como queremos.
Añadimos otra función que reemplaza espacios por guiones, por ejemplo:
space_to_dash() {
local input_string
input_string="$1"
if [[ "$input_string" == "" ]]; then
read -r input_string
fi
echo "${input_string// /-}"
}
Ahora, podemos encadenar las dos funciones usando |
:
echo "My MIXed UPPERcase TEXT" | to_lowercase | space_to_dash
Y el resultado es:
my-mixed-uppercase-text
Como vemos, usando pipes, la solución es mucho más fácil de leer que algo como:
input_string="My MIXed UPPERcase TEXT"
lowercase_string=$(to_lowercase "$input_string")
echo "$(space_to_dash "$lowercase_string")"
O incluso, si sobreescribimos el valor de input_string
:
input_string="My MIXed UPPERcase TEXT"
input_string=$(to_lowercase "$input_string")
echo "$(space_to_dash "$input_string")"