can anyone show me a very simple example of unix script loop - shell

I just need an example of script that repeat all the same actions in a loop til we ask to stop it. Say I want the user to type y or n for exit, how would i implement it. I have something like
echo "Input y or n to exit"
read input
if [ "$input = y ]
then
.......
else
........
fi
For the same script demonstrated in the answer below or maybe other example, how can I have this addition to make the user control the script without having to exit only by pressing control+z

while true; do echo hello; sleep 1; done
will run until you send a signal.

while true; do
commands ...
read -p "Continue (y/n) ? " answer
case "$answer" in
Y*|y*) : ;;
*) break
esac
done
If the user responds with "Y" or "y", do nothing, in which case the loop continues. Otherwise break the loop.

Related

Bash prompt with yes, no and cancel

I'm new in Bash and I'm stuck with writing a prompt function which asks the user a given questions and accepts the answers yes, no and cancel. I know that there are already a lot of answers to similar questions here on SO but I wasn't able to find an answer that fulfills all my requirements.
Requirements:
The ask function must
accept a question as parameter: ask "are you happy?"
accept a answer in [y/n/c]: y, Y, yes, yEs, etc.
return a value based on the answer: true for yes, false for no
the return value must be assignable to a variable to save it for later: answer=$(ask "...?")
the return value must be directly useable by if statements: if ask "...?" then;
be able to halt the complete execution of the calling script for abort: exit
ask again if the answer was not yes, no or cancel
allow a default answer for empty input
work in scripts that use set -e as well as set +e
I came up with the following solution which doesn't work properly:
ask() {
while true; do
read -p "$1 [Y/n/a] " answer
case $(echo "$answer" | tr "[A-Z]" "[a-z]") in
y|yes|"" ) echo "true" ; return 0;;
n|no ) echo "false"; return 1;;
a|abort ) echo "abort"; exit 1;;
esac
done
}
# usage1
if ask "Are you happy?" >/dev/null; then
# ...
fi
# usage2
answer=$(ask "Are you happy?")
For example, the abort does only work when I use -e but then logically the no also causes the script to halt.
I believe it would be just overall simpler to work the same way as read works. Remember to pick a unique name for the namereference.
ask() {
declare -n _ask_var=$2
local _ask_answer
while true; do
read -p "$1 [Y/n/a] " _ask_answer
case "${_ask_answer,,}" in
y|yes|"" ) _ask_var="true" ; break; ;;
n|no ) _ask_var="false"; break; ;;
a|abort ) exit 1; ;;
esac
done
}
ask "Are you happy?" answer
if "$answer"; then echo "Yay! Me too!"; fi

How to make my script menu execute my subscripts in Unix

Sorry in advance since i am new to Unix coding. I have a Bash shell script that generates 2 other subscripts. The main script implements a menu that gives a choice to the user in which script to generate.
I have two problems. The first one is how to make the script that the user selects to execute when he selects it, and the second how to implement input validation in my menu so when the user inputs something different that 1 and 2 to get an error message. This is my code so far:
#!/bin/bash
echo "Welcome to scriptGen."
echo "Please select a script to execute by choosing 1 or 2:"
scripts="bDir mMail"
select option in $scripts
do
echo "You have selected script $option to execute."
done
cat > bDir.sh <<EOF1
#!/bin/bash
#code
EOF1
chmod +x bDir.sh
cat >mMail.sh <<EOF2
#!/bin/bash
#code
EOF2
chmod +x mMail.sh
Thanks for your time!
So you'll probably want a case statement for your user to select their input.
Also, I'm not sure what you're doing with the dynamic writing of scripts, but you'll probably be better off with functions in your code.
Something like the following:
#!/bin/bash
main () {
echo "Welcome to scriptGen."
echo
echo "1: bDir"
echo "2: mMail"
echo -n "Please select a script to execute by choosing 1 or 2: "
read user_input
case $user_input in
1)
bdir
;;
2)
mmail
;;
*)
echo "Unrecognised option '$user_input'. Exiting..."
exit 1
;;
esac
}
bdir () {
echo "Running bDir"
}
mmail () {
echo "Running mmail"
}
main "$#"
Explanation:
main () {
...
}
Creating a function called main. It's a clear enough name to let the user know what function is going to get called first.
echo -n "Please select a script to execute by choosing 1 or 2: "
The -n removes the new-line at the end. This gives a nicer user experience when they're prompted.
read user_input
Read the user's input and store it in the variable user_input. The capture will finish when the user presses enter. However, this can be combined with other flags like -n 1 to capture just 1 character and continue without requiring the user to press enter.
case $user_input in
1)
bdir
;;
2)
mmail
;;
*)
echo "Unrecognised option '$user_input'. Exiting..."
exit 1
;;
esac
A case statement. Given the value of user_input, if it's 1, run the bdir function. If it's 2 run the mmail function. Otherwise, echo the warning and exit.
main "$#"
Run our main function. We use $# to ensure all of the variables passed into the script are also passed into the main function.

Run shell script on windows machine, but the the while do loop does terminate?

I am new to bash script. I want the user to input his choice, but the while-do loop does not terminate. I tired all choices of read [option] but some of them does not work. read -a stop the loop but does not accept the input. I am using windows machine and I am not sure if I need to install some other lib or packages.
I tried: read -p, read -a, read -r , read
function user_input {
while true; do
echo "1. choice 1"
echo "2. choice 2"
read -p "What choice would you like: [1,2] " ANS
case $ANS in
'1')
environment="-A"
break;;
'2')
environment="-B"
break;;
*)
echo "Wrong input, try again";;
esac
done
}
Because you have a case nested in a while, you should use break 2 to break both. Otherwise define a variable CON=true and set it to false in the case.

How to I return back to the main menu, from a function?

I have a problem coming back to the main menu, from a function. My BASH script looks something like this
function functionA(){
while [ "$choice" != x ]; do
echo "Press a to take action, and press b to exit and go back to the main list"
read choice
case $choice in
a)
echo "Now lets do some stuff"
read
...
.....
;;
x)
exit
esac
done
}
while [ "$choice" != x ];do
echo "Main list"
echo "Press a to go to functionA, press b to go to functionB, and press x to exit the program"
read choice
case $choice in
a) functionA
;;
b) functionB
;;
c) exit
esac
done
So basically, if the user is in functionA() and presses x to quit, I want him to come back to the main list, and there he will be able to go to functionA() again or functionB(), or just press x again to quit the whole program.
When you input x in function(), you are calling exit in functionA() which makes whole script exit. Instead just return.

handle user input on background

I want to handle user input, but in the background, like in a new thread.
For example, show a progress bar, and when the user hits R, the progress bar resets, or if the user hits Q, the script exits.
I don't want the script to wait for user input. Just render everything and if the user hits any key do something.
Is it posible in bash?
Thanks in advance.
EDIT: I need the script ALWAYS read user input but do not interrupt the execution of main loop.Complicated I make myself understood in English
_handle_keys()
{
read -sn1 a
test "$a" == `echo -en "\e"` || continue
read -sn1 a
test "$a" == "[" || break
read -sn1 a
case "$a" in
C) # Derecha
if [ $PALETTE_X -lt $(($COLUMNS-$PALETTE_SIZE)) ] ; then
PALETTE_X=$(($PALETTE_X+1))
fi
;;
D) # Izquierda
if [ $PALETTE_X -gt 0 ] ; then
PALETTE_X=$(($PALETTE_X-1))
fi
;;
esac
}
render()
{
clear
printf "\033[2;0f BALL (X:${BALL_X} | Y:${BALL_Y})"
_palette_render # Actualiza la paleta
_ball_render
}
while true
do
LINES=`tput lines`
COLUMNS=`tput cols`
render
_handle_keys
done
In my script, the ball moves (render>_ball_render) only when a key is pressed because _handle_keys wait for user input.
I made a ugly solution with read -t0.1 but don't like this
PD: Sorry for my last comment, the time edit finish in the middle of my editing
Here is a technique that seems to work. I am basing this on Sam Hocevar's answer to Bash: How to end infinite loop with any key pressed?.
#!/bin/bash
if [ ! -t 0 ]; then
echo "This script must be run from a terminal"
exit 1
fi
stty -echo -icanon time 0 min 0
count=0
keypress=''
while true; do
let count+=1
echo -ne $count'\r'
# This stuff goes in _handle_keys
read keypress
case $keypress in
# This case is for no keypress
"")
;;
$'\e[C')
echo "derecha"
;;
$'\e[D')
echo "izquierda"
;;
# If you want to do something for unknown keys, otherwise leave this out
*)
echo "unknown input $keypress"
;;
esac
# End _handle_keys
done
stty sane
If the stty sane is missed (e.g. because the script gets killed with Ctrl-C), the terminal will be left in a weird state. You may want to look at the trap statement to address this.
You might also add "reset" to the end of the script to reset the terminal into original state, or it might look locked. It will clear the screen as well, so one might want to add a pause before executing the command.

Resources