
Estoy escribiendo una función que solicita el nombre de un archivo y luego me aseguro de que la entrada comience con un carácter alfa; si no es así, volverá a solicitar un nombre al usuario hasta que se cumplan los criterios. También muestra un mensaje adicional si el usuario ingresa una ruta (una ruta es cualquier cosa con un '/' para el propósito de esta asignación). Ahí es donde tengo un problema...
aquí está mi código...
#1) make a getname function that will prompt for filename
function getname(){
trap control_c SIGINT
local fname=$1;
#if there is no input prompt user for file name
if [ ! $1 ]; then
read -p "Enter a file name: " fname;
fi;
#until grep is given a valid file name
until ( grep -E '^[a-zA-Z_]\w+$' <<< "$fname" > /dev/null 2>&1); do
#this is were the error is
if echo "$fname" | grep -E '/';
then #this tests if fname is a file directory
echo "Paths are not a legal file name.";
fi;
read -p "Enter a legal file name: " fname;
done
echo "$fname"
}
La instrucción if dentro del bucle hasta no le indicará al usuario que las rutas no son entradas válidas bajo ninguna circunstancia y tampoco produce errores. ¿Cómo implementaría correctamente un grep en una declaración if?
Respuesta1
De hecho, a mí me funciona en Fedora 26 usando GNU bash, version 4.4.12(1)-release (x86_64-redhat-linux-gnu)
. La función sigue preguntando si se proporciona la ruta. Vea el resultado.
[@host testing]$ getname
Enter a file name: ab/sav
ab/sav
Paths are not a legal file name.
Enter a legal file name: abc
abc
[@host testing]$
Sin embargo, encontré dos pequeños problemas. Primero, imprime la ruta y luego vuelve a solicitar información. Esto se puede resolver usando el interruptor grep -q
(q para silencio) en la if
declaración (también funciona para until
, entonces la redirección de salida ya no es necesaria). En segundo lugar, un solo carácter siempre no es válido en el until
bucle. Esto se puede solucionar cambiando \w+
la expresión regular por \w*
.
Respuesta2
grep
La declaración in Until es muy voluminosa, puedes simplificarla.
Puedo sugerir este método:
until [ ! -z "$fname" ]; do
read -p "Enter a legal file name: " fname
grep -E '^[a-zA-Z_]\w+$' <<< "$fname" > /dev/null 2>&1
#check exit code
if [ $? -ne 0 ]; then
echo "Paths are not a legal file name."
fname=""
fi
done
Agregue cualquier condición diferente dentro del bucle hasta si es necesario.
Si desea manejar mensajes para los usuarios, puede usar este truco sin varias read
apariciones de comandos:
fname=""
message_for_user="Enter a file name: "
until [ ! -z "$fname" ]; do
read -p "$message_for_user" fname
grep -E '^[a-zA-Z_]\w+$' <<< "$fname" > /dev/null 2>&1
#check exit code
if [ $? -ne 0 ]; then
echo "Paths are not a legal file name."
fname=""
message_for_user="Enter a legal file name: "
fi
done
La salida será:
Enter a file name: 1laha
Paths are not a legal file name.
Enter a legal file name:
Tenga en cuenta que la primera y la tercera línea son diferentes.
Respuesta3
Puede utilizar una expresión regular en una if
declaración directamente:
if [[ $name =~ ^[a-zA-Z] ]]
o:
if [[ $name =~ ^[:alpha:] ]]