I am writing a script using a function that is it supposed to install a package by giving to the function the name of the package.
I am asking to the user if he wants to install that packet and, to do so, I wrote a regex, but the thing is: my regex is ignored, I can write anything in the output it will works. Howewer, I want the user to write something specific in order to install the package.
#!/bin/bash
OK=$'\033[92m' #GREEN
BASIC=$'\033[96m' #BLUE
RESET=$'\033[0m' #RESET COLOR
CHECK_MARK=$'\033[0;32m\xE2\x9C\x94\033[0m' #CHECKMARK
function install_package() {
answer=""
while [[ ! ($answer =~ ^y$|Y$|Yes$|YES$|yes$|n$|N$|no$|No$|NO$|q$|Q$|Quit$|quit$) ]]
do
echo -en "${BASIC}Do you want to install $1 ? (y|n|q)${RESET}"
answer=$(read)
if [[ $answer =~ ^y$|Y$|Yes$|YES$|yes$ ]]
echo "test"
then
echo -ne "${OK}Installation of $1 ${RESET}"
apt-get install "$1" -y &>/dev/null
echo -e "\\r${CHECK_MARK}${OK} $1 has been installed or is already installed. ${RESET}"
break
fi
done
}
install_package "micro"
echo "test"
And my output:
root@test-deb:/home/user/bashthings# ./p.sh
Do you want to install micro ? (y|n|q)y
test
✔ micro has been installed or is already installed.
test
root@test-deb:/home/user/bashthings# ./p.sh
Do you want to install micro ? (y|n|q)fege8geg655eg
test
✔ micro has been installed or is already installed.
test
root@test-deb:/home/user/bashthings#
It might be confusing but what I am asking is why my regex is not filtering any of what I type ?
CodePudding user response:
Use grep -q
(or egrep -q
for extended version).
# ↓ your string ↓ the pattern
if printf %s "my_string" | grep -q '.*stri.*'
then
echo foo
else
echo bar
fi
Your while
loop condition will look like this:
while printf %s $answer | grep -q '^y$|Y$|Yes$|YES$|yes$|n$|N$|no$|No$|NO$|q$|Q$|Quit$|quit$'
do
: your loop contents here
done
In your conditions, you do not need to use regular expressions at all. Bash has neat syntax construct called case
(similar to C switch
):
read -p "${BASIC}Do you want to install $1 ? (y|n|q)${RESET}" answer
case "$answer" in
[yY])
echo -ne "${OK}Installation of $1 ${RESET}"
# […]
echo -e "\\r${CHECK_MARK}${OK} $1 has been installed or is already installed. ${RESET}"
;;
[nN])
: do nothing
;;
[qQ])
exit 0
esac
Case uses simple patterns. y
means “exactly y
”, you can use [yY]
to provide multiple character variants. Separate multiple patterns by |
for “or”. Asterisk (*
) means “zero or more characters”, question mark (?
) is one character.
Note also that I used read -p PROMPT VAR
to read a text into a variable while displaying a prompt. See read
help for more information, it provides quite a lot of features for reading text in such scripts.
CodePudding user response:
I'd take advantage of the nocasematch
shell option that can compare
strings case-insensitively, and a case
statement can add readability:
shopt -s nocasematch
function install_package() {
local package=$1
local answer
while true; do
echo -en "${BASIC}Do you want to install $package ? (y|n|q)${RESET}"
read -r answer
case $answer in
n | no | q | quit)
echo "ok, bye"
exit
;;
y | yes)
echo -ne "${OK}Installation of $package ${RESET}"
#apt-get install "$package" -y &>/dev/null
echo -e "\\r${CHECK_MARK}${OK} $package has been installed or is already installed. ${RESET}"
break
;;
esac
done
}
But the select
statement is very useful for these kind of prompts: it
prints a menu and the user selects one of the options. It loops until the user enters a valid value.
function install_package() {
local package=$1
local answer
printf "${BASIC}Do you want to install $package ?${RESET}\n"
PS3="Your answer: "
select answer in Yes No; do
case $answer in
No)
echo "ok, bye"
break
;;
Yes)
echo -ne "${OK}Installation of $package ${RESET}"
#apt-get install "$package" -y &>/dev/null
echo -e "\\r${CHECK_MARK}${OK} $package has been installed or is already installed. ${RESET}"
break
;;
esac
done
}