Exiting "while true; do" loop in shell script prompt - linux

My current project on Linux is to make a script that has three options: yes, no and false input. The last one would cause the script to loop back to the question, but with my current method, even the "yes" option loops back to the original statement. I'm incredibly confused as to how I can fix this. Here's the part of the script I mean:
while true; do read -p "Do you want to run the script now? (Y/N) " yn
case $yn in
[Yy]* ) echo "Permission granted, running commands...";;
[Nn]* ) echo "Operation aborted, exiting..." && exit;;
* ) echo "Incorrect input detected, exiting...";;
esac
done
... more code
How can I make the first command execute the rest of the script, while keeping the function of this loop for the last command at hand?

It seems you want to break out of the loop and execute the "more code" that comes after. That's what a break command is for.
while true; do read -p "Do you want to run the script now? (Y/N) " yn
case $yn in
[Yy]* ) echo "Permission granted, running commands..." && break;;
[Nn]* ) echo "Operation aborted, exiting..." && exit;;
* ) echo "Incorrect input detected, exiting...";;
esac
done

Related

Online bash script that calls another script ignore functions and commands

I wrote a bash script which downloads another script. To run the first script, I use
curl -s get.domain.com | bash
I use the following script to download:
#!/bin/bash
setup_dir=$(dirname "$(readlink -f $0)")
setupbuild=$vmsetup_dir/setupbuild
fileslocation=files.domain.com
wget -r -np -nH -A .sh ${fileslocation} -P ${setupbuild}
find ${setupbuild} -name "*.sh" -exec chmod +x {} +
exec ${vmsetupbuild}/menu.sh
At the end of the script, I want to run the downloaded script. This is where things go wrong and I don't understand it at all.
The menu of the called script seems to work. However, when a choice is made, the echo is ignored and the exit also doesn't do anything.
If I start the script from the prompt, everything works as expected.
I have tried to put an if in various places, but that also didn't help. It seems like certain things in the called script are being ignored.
menu.sh:
#!/bin/bash
main_menu() {
clear
echo "1) Option 1"
echo "2) Option 2"
echo "3) Other option"
echo "4) Quit"
read -p "Enter your choice: " main_menu_choice
case $main_menu_choice in
1)
option1
main_menu
;;
2)
option2
main_menu
;;
3)
other_option
main_menu
;;
4)
echo "Exit"
exit 1
;;
*)
echo "Invalid option. Please try again."
sleep 2
main_menu
;;
esac
}
option1() {
echo "You chose option1."
sleep 2
}
option2() {
echo "You chose option2."
sleep 2
}
other_option() {
echo "You chose other option."
sleep 2
}
main_menu
The script is reading standard input from the pipe, so you can't respond to prompts from the terminal.
When it executes menu.sh you can redirect input back to the terminal.
exec ${vmsetupbuild}/menu.sh < /dev/tty

bash input/ouput to a log file

I have a bash script with below statement. I need to output both the question "Are you happy? and the answer "yes" or "no" to a log file. I'm able to get the answer to log file with "echo "$yn" >>log1.log 2>&1" but not the question (read command)
while true; do
read -p "Are you happy? " yn
case $yn in
[Yy]* ) break;;
[Nn]* ) exit;;
* ) echo "Please answer yes or no.";;
esac
done
echo "$yn" >>log1.log 2>&1
What I have tried:
read -p "Are you okay?" yn > log.log 2>&1
This will indeed work, however when I run my scrip the question is not displayed.
The only way I found is to echo "Are you happy? $yn" >>log1.log 2>&1
The problem with this is that I have several prompts with long statements, I like to keep my scripts nice and short
The redirect only applies to the echo. You need to add a similar redirect afther the done. (This will also redirect the error message which you echo from within case, which incidentally should go to standard error):
while true; do
read -p "Are you happy? " yn
case $yn in
[Yy]* ) break;;
[Nn]* ) exit;;
* ) echo "Please answer yes or no." >&2;;
esac
done >>log1.log 2>&1
echo "$yn" >>log1.log
or put the entire sequence of commands inside parenthes or braces.
{ while true; do
read -p "Are you happy? " yn
case $yn in
[Yy]* ) break;;
[Nn]* ) exit;;
* ) echo "Please answer yes or no." >&2;;
esac
done
echo "$yn"; } >>log1.log 2>&1
Like you discovered, and like the term should reveal, a redirection causes the output to go to another place (so a file instead of your terminal, in this case). If you want it displayed on the terminal as well, tee does that, but it's probably not suitable for interactive scripts (because you can't include standard input in the output).
tripleee$ cat >nst
#!/bin/bash
while true; do
read -p "Are you happy? " yn
case $yn in
[Yy]*) break;;
[Nn]*) exit;;
*) echo "Please answer yes or no." >&2;;
esac
done
echo "$yn"
^D
tripleee$ chmod +x ./nst
tripleee$ ./nst 2>&1 | tee log1.log
Are you happy? forget it
Please answer yes or no.
Are you happy? no
tripleee$ cat log1.log
Are you happy? Please answer yes or no.
Are you happy? tripleee$
Perhaps you are actually looking for the script command?
tripleee$ script typescript ./nst
Script started, output file is typescript
Are you happy? forget it
Please answer yes or no.
Are you happy? yes ma'am
yes ma'am
Script done, output file is typescript
tripleee$ nl -ba typescript
1 Script started on Thu Oct 26 20:34:04 2017
2 command: ./nst
3 Are you happy? forget it
4 Please answer yes or no.
5 Are you happy? yes ma'am
6 yes ma'am
7
8 Script done on Thu Oct 26 20:34:11 2017
Note that the typescript file will contain any edits done by the user, i.e. typos and their correction will be included, with the various display codes used by the terminal to execute the edits.

Shell error when using multiline ssh command inside user prompt check

Running into a bit of an issue while trying to add a user prompt check to a existing script which was already working.
Here is the existing script, which is working...
#!/bin/sh
echo "**** Pulling changes into Production"
ssh user#example.com "$( cat <<'EOT'
cd example.com/html/ || exit
unset GIT_DIR
git pull
EOT
)"
Here is my modified script with a user prompt, which is broken.. and it is only broken when I add the ssh line. Works perfectly with just echoes.
#!/usr/bin/env bash
while true; do
read -p "Are you sure you want to pull changes into production? [y/N] " yn
case $yn in
[Yy]* )
ssh user#example.com "$( cat <<'EOT'
cd example.com/html/ || exit
unset GIT_DIR
git pull
EOT
)";
exit;;
[Nn]* )
echo "!!!! CANCELLING !!!!";
exit;;
* ) echo "Please answer yes or no.";;
esac
done
The error I'm getting is...
Syntax error: end of file unexpected (expecting ")")
EOT must appear at the beginning of the line. Your EOT appears somewhere in between, with lots of leading spaces.
Replace
EOT
By
EOT

if statement not working in cron

I have the following code: (record.sh)
cd $(dirname $0)
dt=$(date '+%d/%m/%Y %H:%M:%S');
echo $dt;
read action < /home/nfs/sauger/web/pi/action.txt
echo $action;
if [[ $action == *"start"* ]]
then
echo "start recording"
./gone.sh
exit 1
elif [[ $action == *"stop"* ]]
then
echo "stop recording"
./gone.sh
exit 1
else
#More stuff done here
fi
When I run this script manually the output is the following:
19/01/2016 19:07:11
start
start recording
If the same script is run via a (root) cronjob, the output is the following:
19/01/2016 19:07:01
start
As you can see, the file "action.txt" has been read without a problem ("start" is logged both times) so this should not be an issue of permissions or wrong paths. But when run as a cronjob, the if-statement is not called. No "start recording" appears.
So my question is: Why does the if-statement work when I call the script manually, but not when this is done via cron?
Your script is written for bash; these errors are almost certainly indicative of it being run with /bin/sh instead.
Either add an appropriate shebang and ensure that it's being called in a way that honors it (/path/to/script rather than sh /path/to/script), or fix it to be compatible. For instance:
case $action in
*start*)
echo "start recording"
./gone.sh
exit 1
;;
*stop*)
echo "stop recording"
./gone.sh
exit 1
;;
esac

Validate input from bash

I need to make a bash script that takes user input and does some validation.
The input is small. I just need to get a user choice "yes" or "no" and a file path and make sure the input is indeed a filepath and that he entered yes or no.
How can I validate the user input?
from your bash prompt type
help read
example:
step 1.
pete#ruthie ~ $ read -p "Yes or No :" ANSWER
Yes or No :Yes
pete#ruthie ~ $ echo $ANSWER
Yes
step 2.
case $ANSWER in
Y* | y* ) echo "ANSWER is yes" ;;
N* | n*) echo ANSWER is no;;
*) echo "Unclear Response" ;;
esac
ANSWER is yes
Or all on one line:
case $ANSWER in Y* | y* ) echo "ANSWER is yes" ;; N* | n*) echo ANSWER is no;; *) echo "Unclear Response" ;; esac
ANSWER is yes
So something vaguely like::
read -p "Enter File Name :" FILE_TO_CHECK
if [ ! -e "$FILE_TO_CHECK" ]; then
echo -e "There is no file called $FILE_TO_CHECK \n please check spelling"
else
echo "Congratulations found $FILE_TO_CHECK. "
ls -lah $FILE_TO_CHECK
read -p "Process $FILE_TO_CHECK ? Y or N : PROCEED
case $PROCEED in
Y* | y*)
##call function or system command to do something with this data
foo $FILE_TO_CHECK
;;
* )
echo -e "Note $USER\n No action taken by $0 on $FILE_TO_CHECK"
;;
esac
fi
The test command is your friend. You really need to learn its ways ASAP.
help [
and
help test
The "help bashthing" command is a great quick reminder.
see also: the Advanced Bash Scripting Guide (ABS)
http://tldp.org/LDP/abs/html/
FWIW:
This is a very simple example and wont accommodate much in the way of unexpected user input.
I would probably call functions for each step of this as then I could conditionally represent the user with another chance.
The case tests nested like this is plain ugly :) === hard to get neat and read later
There are other ways to achieve all this try zenity for a GTK style GUI.
The A.B.S is excellent but dont try to eat it all at once !

Resources