Comprender los comandos read, echo y grep en una línea de comandos bash

Comprender los comandos read, echo y grep en una línea de comandos bash

¿Alguien puede explicar qué sucede en esta línea de bash paso a paso? Soy nuevo aquí y estoy tratando de entender cómo funciona este código, especialmente desde echo:

read char; echo -e "YES\nNO\n" | grep -i $char

Respuesta1

Los comandos en la línea leen una cadena en la variable char, probablemente de forma interactiva por parte del usuario.

La canalización echo+ grepintenta determinar si la cadena ingresada es afirmativa o no. Lo hace haciendo coincidir las palabras YESy NOcon la cadena ingresada (con la cadena ingresada como patrón), sin distinguir entre mayúsculas y minúsculas. Si el usuario ingresa un carácter mayúscula o minúscula o una subcadena presente en la palabra YES, el resultado sería YES; si ingresaron un carácter mayúsculo o minúsculo o una subcadena presente en la cadena NO, el resultado sería NO. Ingresar algo así maybedaría como resultado una salida vacía.

La desventaja de este enfoque es que si el usuario ingresa, por ejemplo, .ambos YESy NOcoincidirían, ya que greptrataría el punto como una expresión regular que coincide con cualquier carácter. Dado que $charno está entre comillas en la llamada a grep, también tendría el potencial de causar un ataque de denegación de servicio contra la máquina si el usuario ingresa un patrón global de shell como /*/*/*/*/../../../../*/*/*/*input (ejemplo tomado deImplicaciones de seguridad de olvidarse de citar una variable en shells bash/POSIX). También podría generar resultados confusos con el comando al ingresar, por ejemplo, -r -o -e . /(daría salida a cada carácter de cada archivo no binario en una línea precedida por la ruta del archivo del que forma parte).

El código que muestra es "extraño e inusual" porque utiliza la entrada del usuario como algo esencialmentecódigo, es decir, utiliza la entrada del usuario comopatróny pruebas estáticasdatoscontra este patrón variable. Esto es lo opuesto a lo que se suele hacer, que es tomar la entrada del usuario y probar estos datos variables con un patrón estático.

Es más común utilizar código similar al siguiente:

read -p 'Yes/[N]o: ' yesno
if [[ $yesno == [Yy]* ]]; then
   # code for affirmative
else
   # code for non-affirmative
fi

El código anterior lee una cadena del usuario y prueba si comienza con un carácter yo un Ycarácter. La primera rama de la ifdeclaración se tomaría si así fuera, pero elsede lo contrario se tomaría la rama de forma predeterminada.

Obviamente, también puedes probar la palabra completa YES, o [Yy][Ee][Ss]una coincidencia que no distinga entre mayúsculas y minúsculas, o hacer un bucle de entrada adecuado con verificación:

while true; do
    read -p 'Yes/No: ' yesno

    if [ "$yesno" = Yes ] || [ "$yesno" = No ]; then
        break
    fi

    echo 'Please enter "Yes" or "No"' >&2
done

# $yesno is either Yes or No here

(o algo similar).

Observe cómo los dos códigos de ejemplo anteriores utilizan la entrada del usuario exclusivamente como datos y nunca como patrón.

Reescribir mínimamente su comando original a algo un poco idiomático (pero funcionalmente diferente, y probablemente no infalible) lo convertiría en

read yesno; printf '%s\n' "${yesno^^}" | grep -i -w -E 'yes|no'

Esto devolvería mayúsculas YESo NOsi el usuario escribió yeso no. Esto es funcionalmente diferente ya que requiere que el usuario escriba algo más que solo eun yes, por ejemplo.

Respuesta2

Bueno, tomemos cada comando por turno:

read char

Esto leerá desde la entrada estándar (normalmente su teclado, pero puede ser un archivo indirecto o una secuencia canalizada; consulte a continuación) y colocará los datos recibidos en una variable denominada char.

echo -e "YES\nNO\n"

echomostrará en la salida estándar (normalmente el terminal) los parámetros proporcionados. El -ecambio (a menudo, pero no siempre; echoes un poco problemático con respecto a la implementación consistente) le permitirá eescapar de ciertos caracteres para realizar algún formateo rudimentario. En este caso, se utiliza \n, que es un escape n, que es una abreviatura de newline.

grep -i $char

grepes una herramienta para buscar entradas proporcionadas para ver si hay coincidencias para el patrón proporcionado. El -iinterruptor le indica que sea una ibúsqueda que no distinga entre mayúsculas y minúsculas.

El espacio |entre los comandos echoy grepes una "tubería". Esto conecta la salida del primer comando con la entrada del segundo, lo que significa que grepbuscará en este corpus el patrón reflejado en el contenido de la variable char:

YES
NO

El resultado práctico de esta secuencia de comandos es observar la entrada proporcionada (se supone que, según el nombre de la variable, es un solo carácter, pero esto no está marcado). Si este carácter es Y, E, S, y, eo s, la salida será YES. Si este carácter es N, O, no o, la salida será NO. Sin embargo, si (por ejemplo) la entrada es yoo ne, no se generará nada.

Como se señaló anteriormente, la presunción de que la entrada es un carácter no se verifica. Este no es el único antipatrón en la secuencia de comandos de ejemplo dada. Por ejemplo, las variables no se citan; y grepse utiliza una herramienta de expresión regular ( ) sin que la entrada se analice en busca de comodines de expresiones regulares.

Respuesta3

Se lee un "carácter" (más bien: una cadena) desde /dev/stdin. Significado: lo escribes.

Luego se envían dos líneas a /dev/stdout. Es decir, tu consola.

Y a través de la tubería (el "|"), esto se grep-ed para la versión de su entrada que no distingue entre mayúsculas y minúsculas.

Esto significa que si ingresa "barra", simplemente terminará sin ningún resultado aparente, pero si ingresa, digamos, "y", entonces aparecerá la línea "SÍ", lo más probable es que incluso resalte la "Y".

información relacionada