¿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
+ grep
intenta determinar si la cadena ingresada es afirmativa o no. Lo hace haciendo coincidir las palabras YES
y NO
con 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í maybe
daría como resultado una salida vacía.
La desventaja de este enfoque es que si el usuario ingresa, por ejemplo, .
ambos YES
y NO
coincidirían, ya que grep
trataría el punto como una expresión regular que coincide con cualquier carácter. Dado que $char
no 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 y
o un Y
carácter. La primera rama de la if
declaración se tomaría si así fuera, pero else
de 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 YES
o NO
si el usuario escribió yes
o no
. Esto es funcionalmente diferente ya que requiere que el usuario escriba algo más que solo e
un 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"
echo
mostrará en la salida estándar (normalmente el terminal) los parámetros proporcionados. El -e
cambio (a menudo, pero no siempre; echo
es un poco problemático con respecto a la implementación consistente) le permitirá e
escapar 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 n
ewline.
grep -i $char
grep
es una herramienta para buscar entradas proporcionadas para ver si hay coincidencias para el patrón proporcionado. El -i
interruptor le indica que sea una i
búsqueda que no distinga entre mayúsculas y minúsculas.
El espacio |
entre los comandos echo
y grep
es una "tubería". Esto conecta la salida del primer comando con la entrada del segundo, lo que significa que grep
buscará 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
, e
o s
, la salida será YES
. Si este carácter es N
, O
, n
o o
, la salida será NO
. Sin embargo, si (por ejemplo) la entrada es yo
o 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 grep
se 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".