do-while loop using user input in shell scritping [duplicate] - linux

This question already has answers here:
Why should there be spaces around '[' and ']' in Bash?
(5 answers)
Closed 2 years ago.
I am a beginner in bash scripting. and i look for similar questions but none gave me the results am looking for.
I want to create a shell that keep giving the user some options to choose from while the choice is not exit
Here is my code
choice=0
while [$choice!=4]
do
echo "please choose the operation you want!"
echo "1) Delete Data"
echo "2) Insert Data"
echo "3) Get Number of customers"
echo "4) Exit"
choice=$1
if [$choice=1]; then
echo "you have chosen to Delete Data"
elif [$choice=2]; then
echo "you have chosen to Insert Data"
elif [$choice=3]; then
echo "you have chosen to Get number of customers"
fi # EOF if
done
As you can see that i want my code to keep asking for the user options until the answer is not exit.
My Question is this code gives me an infinite loop.

Bash, ksh or zsh provides you with the select command that is exactly designed to present numbered options menu:
To get the usage of the select command, type help select in your bash terminal.
select: select NAME [in WORDS … ;] do COMMANDS; done
Select words from a list and execute commands.
The WORDS are expanded, generating a list of words. The set of expanded words is printed on the standard error, each preceded by a number. If in WORDS is not present, in "$#" is assumed. The PS3 prompt is then displayed and a line read from the standard input. If the line consists of the number corresponding to one of the displayed words, then NAME is set to that word. If the line is empty, WORDS and the prompt are redisplayed. If EOF is read, the command completes. Any other value read causes NAME to be set to null. The line read is saved in the variable REPLY. COMMANDS are executed after each selection until a break command is executed.
Exit Status:
Returns the status of the last command executed.
Here is an implementation of it with your selection menu:
#!/usr/bin/env bash
choices=('Delete Data' 'Insert Data' 'Get Number of customers' 'Exit')
PS3='Please choose the operation you want: '
select answer in "${choices[#]}"; do
case "$answer" in
"${choices[0]}")
echo 'You have chosen to Delete Data.'
;;
"${choices[1]}")
echo 'You have chosen to Insert Data.'
;;
"${choices[2]}")
echo 'You have chosen to Get number of customers.'
;;
"${choices[3]}")
echo 'You have chosen to Exit.'
break
;;
*)
printf 'Your answer %q is not a valid option!\n' "$REPLY"
;;
esac
done
unset PS3
Another implementation of the select command, using arguments rather than an array of choices:
#!/usr/bin/env ksh
PS3='Please choose the operation you want: '
set -- 'Delete Data' 'Insert Data' 'Get Number of customers' 'Exit'
select answer; do
case "$answer" in
"$1")
echo 'You have chosen to Delete Data.'
;;
"$2")
echo 'You have chosen to Insert Data.'
;;
"$3")
echo 'You have chosen to Get number of customers.'
;;
"$4")
echo 'You have chosen to Exit.'
break
;;
*)
printf 'Your answer %q is not a valid option!\n' "$REPLY"
;;
esac
done

If you want to use while loop with conditional 'case' syntax, try this:
while true
do
echo "1) Delete Data"
echo "2) Insert Data"
echo "3) Get Number of customers"
echo "4) Exit"
echo -ne "Enter your choice [0-4] > \c"
read choice
case "$choice" in
1) echo "you have chosen to Delete Data" ; break
;;
2) echo "you have chosen to Insert Data"; break
;;
3) echo "you have chosen to Get number of customers"; break
;;
4) exit
;;
*) clear
;;
esac
done

i found the error. it was statement typing issue not in the algorithm
my new code is
while [ "$(read choice)"!="4" ]
do
if [ "$choice"="1" ]; then
echo "you have chosen to Delete Data"
elif [ "$choice"="2" ]; then
echo "you have chosen to Insert Data"
elif [ "$choice"="3" ]; then
echo "you have chosen to Get number of customers"
fi # EOF if
echo "please choose the operation you want!"
echo "1) Delete Data"
echo "2) Insert Data"
echo "3) Get Number of customers"
echo "4) Exit"
done

Related

Create an interactive Shell prompt menu from a dynamic list?

The following prompt should allow the user to make a selection based on the populated list that is outputted to an array, then prints the list with its index, and asks user to select a number from the list, then sets it to a variable. Only one choice is allowed, if user specifies an incorrect option, the script will prompt to select a correct number.
Multiple devices detected, please select one from the list:
1. Device1
2. Device2
3. Device3
1
You have selected device Device1
The code below is not functional and has many syntax errors, first I would like the script to detect if the output of arr=($(ip ad|awk '/state UP/ {print $2}')) contains multiple entries, if so run the script, otherwise set a default value.
The case statement is not dynamic however, if more then 2 cases like below it will fail, perhaps a loop?
host_interfaces()
{
arr=($(ip ad|awk '/state UP/ {print $2}'))
echo "Multiple devices detected, please select one from the list:"
for i in "${!arr[#]}"; do
printf "%s%s\n" "$i. " "${arr[$i]}"
done
PS3='Please enter your choice: '
select opt in "${arr[#]}"
do
case $opt in
"$opt")
echo "You have selected device $opt"
export HOST_INTERFACE=$opt
;;
*) echo "invalid option
break
;;
esac
done
}
This, maybe?
host_interfaces()
{
local opt='' h=''
arr=($(ip ad|awk '/state UP/ {print $2}'))
if [ "${#arr[#]}" -eq 1 ]; then
echo "One single device detected"
h="${arr[0]}"
elif [ "${#arr[#]}" -gt 1 ]; then
echo "Multiple devices detected, please select one from the list:"
PS3='Please enter your choice: '
select opt in "${arr[#]}"
do
case "$opt" in
"")
echo "Invalid choice"
h=''
;;
*)
echo "You have selected device $opt"
h="$opt"
break
;;
esac
done
else
echo "No device detected"
fi
echo "Selected device: ${h:-none}"
export HOST_INTERFACE="$h"
[ -z "$h" ] && return 1 || return 0
}
Note that the function returns 1 if no valid device was found or selected, else 0. So you can use it with:
if host_interfaces; then
echo "HOST_INTERFACE = $HOST_INTERFACE"
else
echo "No device selected"
fi
A solution:
#! /bin/bash
declare HOST_INTERFACE=
function host_interfaces() {
local -a arr=($(ip ad | awk '/state UP/ {gsub(/:/, "", $2); print $2}'))
if [ "${#arr[#]}" -eq 1 ]; then
HOST_INTERFACE="${arr[0]}"
return 0
fi
local opt=
HOST_INTERFACE=
echo "Multiple devices detected, please select one from the list:"
PS3='Please enter your choice: '
# Add "Quit" value to the items
select opt in "${arr[#]}" Quit; do
# "opt" does not contains the number but the associated value
case $opt in
"Quit")
#
break
;;
"")
# No value found
echo "invalid option"
;;
*)
echo "You have selected device $opt"
export HOST_INTERFACE=$opt
break
;;
esac
done
}
host_interfaces
It is possible to simply use dialog here.
dialog --backtitle "Device selection" --title "Multiple devices detected" --menu "please select one from the list:" 10 45 4 1 "Device1" 2 "Device2" 3 "Device3"
See man dialog

Yes or No in Bash Script

I have a set of 100 questions. My requirement is when a user enter "yes", then question 1 should appear. If not, directly it go to question 2. Like that it should go on till 100 questions. Any lead would be appreciated.
This is what I tried, but it is failing.
#!/bin/bash
echo "Execute question1 "
select result in Yes No
do
echo "How to see apache config file"
exit
done
echo "execute question2"
select result in Yes No Cancel
do
echo "Command for listing processes"
exit
done
Thanks in advance
Here is a way to do this with an array.
#!/bin/bash
questions=(
"How to see apache config file"
"Command for listing processes"
"My hovercraft is full of eels"
)
for((q=0; q<${#questions[#]}; q++)); do
echo "Execute question $q?"
select result in Yes No; do
case $result in
Yes)
echo "${questions[q]}";;
esac
break
done
done
Using select for this seems rather clumsy, though. Perhaps just replace it with
read -p "Execute question $q? " -r result
case $result in
[Yy]*) echo "${questions[q]}";;
esac
Having just a list of questions still seems weird. With Bash 5+ you could have an associative array, or you could have a parallel array with the same indices with answers to the questions. But keeping each question and answer pair together in the source would make the most sense. Maybe loop over questions and answers and assign every other one to an answers array, and only increment the index when you have read a pair?
pairs=(
"How to see Apache config file"
"cat /etc/httpd.conf"
"Command for listing processes"
"ps"
"My hovercraft is full of what?"
"eels"
)
questions=()
answers=()
for((i=0; i<=${#pairs[#]}/2; ++i)); do
questions+=("${pairs[i*2]}")
answers+=("${pairs[1+i*2]}")
done
This ends up with two copies of everything, so if you are really strapped for memory, maybe refactor to just a for loop over the strings and get rid of the pairs array which is only useful during initialization.
Use an array of questions and loop over it, like this:
#!/bin/bash
n=1
questions=(
'How to see apache config file'
'Command for listing processes'
)
check_user_input(){
read -p "y/n " input
case $input in
[Yy]*) return 0;;
[Nn]*) return 1;;
*) check_user_input;;
esac
}
for question in "${questions[#]}"; {
echo "Execute question $n"
check_user_input && echo "$question"
((n++))
}
Here is a straight forward example. Play with it.
#!/bin/bash
echo "Type 'y' for yes, 'n' to skip or 'q' to quit and press Enter!"
for((i=1; i < 101; ++i)); do
echo 'Execute question '$i
while read user_input; do
if [[ "$user_input" = 'q' ]]; then
break 2
elif [[ "$user_input" = 'n' ]]; then
break
elif [[ $i -eq 1 ]]; then
echo 'How to see apache config file?'
break 2 # Change from "break 2" to "break" for the next question.
elif [[ $i -eq 2 ]]; then
echo 'Command for listing processes.'
break 2 # Change from "break 2" to "break" for the next question.
else
echo "Wrong input: $user_input"
echo "Type 'y' for yes, 'n' to skip or 'q' to quit and press Enter!"
fi
done
done
echo 'Finished'

Optional commands in UNIX

I'm trying to create a session in unix that will allow my to ask a simple question and then ask different questions varying on the answer.
For example if I were to ask
'Enter a choice (quit/order)'
if 'quit' is entered then program should close
if 'order' is entered then the program should continue asking further questions.
If you can help that would be great! Thanks!
#!/bin/bash
echo "Lots of choices.."
read -p "What is your choice? " choice
echo "Your choice was $choice"
if [ $choice == "quit" ]
then
echo "Exiting.."; exit 0
fi
if [ $choice == "order" ]
then
echo "Doing some other stuff.."
fi
This is where the shell's select command comes in handy. I'm going to assume you're using bash
PS3="Enter a choice: "
select answer in Quit Order; do
case $answer in
Quit) echo "Thanks for playing."; exit ;;
Order)
# select is like an infinite loop: you need to break out of it
break
;;
*) echo "Use the numbers to select your answer." ;;
esac
done
# carry on with the next question

Bash shell script remove text from file/ find text in file [duplicate]

This question already has answers here:
Does not work to execute command in double brackets in bash
(3 answers)
Getting "command not found" error while comparing two strings in Bash
(4 answers)
How to delete from a text file, all lines that contain a specific string?
(21 answers)
using awk with column value conditions
(6 answers)
Closed 5 years ago.
I am new to Bash and was wondering if someone could give me some insight on how I can make this program work more accurately.
Goal: To write a bash shell script that presents a menu to the user with the options of add a contact, remove a contact, find a contact, list all contacts, and exit the program.
This is my code so far:
#!/bin/bash
touch contacts.dat
echo "Select one of the following options:"
echo "-------------------------------------"
echo "1. Add a contact"
echo "2. Remove a contact"
echo "3. Find a contact"
echo "4. List all contacts"
echo "5. Exit the program"
read -p "Enter a choice (1-5): " choice
echo
#
case "$choice" in
1)
read -p "Enter a name: " name
read -p "Enter an email address: " email
echo "$name , $email" >> contacts.dat
;;
2)
read -p "Enter a name: " name
if (grep -q name contacts.dat) then
grep -v name contacts.dat > deletedNames.dat
echo "$name was removed from the file."
else
echo "$name does not exist in the file."
fi
;;
3)
read -p "Enter a name: " name
if (grep -q name contacts.dat) then
echo "$name , $email"
else
echo "The $name was not found."
fi
;;
4)
sort -k 1 contacts.dat
;;
5)
echo "Thank you for using this program!"
# break?
exit 1
;;
*)
echo "Please enter a valid choice (1-5)."
;;
esac
The program seems to work with options 1, 4, and 5. However, not with 2 and 3.
How can I get 2 and 3 to remove the contact and find the contact (respectfully)? Thank you in advance for any help you may be able to offer.

Bash if string = this or that [duplicate]

This question already has answers here:
How do I prompt for Yes/No/Cancel input in a Linux shell script?
(37 answers)
Closed 2 years ago.
Trying to write a script which will read what a user has imput... I know it's basic but im stuck on the first if..
echo "Please enter yes or no (y/n)?"
read string
if [ $string = "y" -o "n" ]
then
echo "User selected $string"
else
echo "You didn't enter y/n !!!"
fi
I would like it to be if [ $backup = "y" or "n" ]
Any ideas?
Use this syntax in bash :
if [ "a string" = "another one" ] ; then
# Whatever
fi
For multiple conditional statements such as OR, use:
if [ "a string" = "another one" ] || [ "$foo" = "bar" ] ; then
# Whatever
fi
bash also supports the non-standard [[ ... ]] expression, which can process a compound comparison using a single command, rather than 2 [ commands:
if [[ "a string" = "another one" || $foo = "bar" ]]; then
# Whatever
fi
Not the question you actually asked, but... You told the user to enter "yes" or "no" but only test for y or n - sure, you gave them a hint but users are hint-resistant. So maybe a looser test is in order:
echo "Please enter yes or no (y/n)"
read string
case "$string" in
[yY]* | [nN]*) echo "User entered $string" ;;
*) echo "I don't understand '$string'" ;;
esac
That will recognize any variation that begins with Y or N - usually that's good enough, but you could tighten up the tests. Also, since you'll probably want to do something different with a yes or no response you can expand the case (I've also tightened the tests in this one):
case "$string" in
[yY] | [yY][eE][sS]) echo "Here's where you process yes" ;;
[nN] | [nN][oO]) echo "And here you deal with no" ;;
*) echo "I don't understand '$string'" ;;
esac
You could do this with if statements but I find case more readable when more than two alternatives are possible and the test is appropriate to case syntax.
You can also try:
echo "Please enter yes or no (y/n)?"
read string
if [[ "$string" =~ ^(y|n)$ ]]
then
echo "User selected $string"
else
echo "You didn't enter y/n !!!"
fi
I nice solution is would be with case, which is easier to extend if you want to make your input more complex
case $string in
y|n) echo "User selected $string"
;;
*) echo "You didn't enter y/n !!!"
;;
esac
From there you can easily modify it to accept Uppercase or whatever:
case $string in
y|Y) echo "yes, Sir!"
;;
n|N) echo "No, can't do"
;;
*) echo "Say what?"
;;
esac
Check case statements for more info.

Resources