unexpected fi in bash script - bash

This is the script and I keep getting an unexpected fi error. What am I missing? .. (I started using [] for the if statement but since I'm using this command I deleted the [] .. Is it ok this way?)
if type "java" 2>&1;
then
echo "All ok . . . ";
exit
else
read -n1 -r -p "Yo need to install"
while true; do
echo "Want to install??"
select yn in "y" "n"; do
case $yn in
y ) echo "Installing here..."; break;;
n ) echo "Ok... stopping..."; exit;;
esac
done
exit
fi
thanks!

while ends with done, not exit. Try this:
if type "java" 2>&1;
then
echo "All ok . . . ";
exit
else
read -n1 -r -p "Yo need to install"
while true; do
echo "Want to install??"
select yn in "y" "n"; do
case $yn in
y ) echo "Installing here..."; break;;
n ) echo "Ok... stopping..."; exit;;
esac # <-- ending `case`
done # <-- ending `select`
done # <-- while ends with `done`, not `exit`!
fi # <-- ending `if`

You have an exit before the last fi; I suppose that should be a done.

Related

POSIX equivalent to prinf -v

I have a script that substitutes a variable with another value, depending on the input:
#!/bin/bash
prompt()
{
while true; do
read -p "Do you wish to install this program? " "ANSWER"
case "$ANSWER" in
[Yy]* ) printf -v "$1" %s "true"; break;;
[Nn]* ) printf -v "$1" %s "false"; break;;
* ) echo "Please answer yes or no.";;
esac
done
}
prompt "QUESTION"
if [ "$QUESTION" = "true" ]; then
echo "SUCCESS"
elif [ "$QUESTION" = "false" ]; then
echo "FAILURE"
fi
This works fine, though i want the script to be POSIX compliant. I use #!/bin/sh for all my scripts, though printf -v is bashism. How can i modify this program? Is there an equivalent function i could use? Thanks!
read itself can set the variable whose name is in $1. However, you still need read ANSWER first, so that you can examine the response. Once it's done, you can use read and a here-document to transfer the value of $ANSWER to whatever variable prompt requests.
prompt () {
while :; do
printf "Do you wish to install this program? " >&2
read ANSWER
case $ANSWER in
[Yy]* ) ANSWER=true ; break ;;
[Nn]* ) ANSWER=false; break ;;
* ) printf 'Please answer yes or no.\n' >&2 ;;
esac
done
read "$1" <<EOF
$ANSWER
EOF
}
You can use a command substitution to ensure the ANSWER is not set in the global environment.
prompt () {
read "$1" <<EOF
$(while :; do
printf "Do you wish to install this program? " >&2
read ANSWER
case $ANSWER in
[Yy]* ) printf true; break ;;
[Nn]* ) printf false; break ;;
* ) printf 'Please answer yes or no.\n' >&2 ;;
esac
done
)
EOF
}

what is the best way to go back to the beginning of a script?

I have a script with several inputs, the script eventually initiates a download, once the download is complete i would like to do prompt the user to start the process over if they want to download something else.
while true;do
read -p "Is this correct? (yes/no/abort) " yno
case $yno in
[Yy]*) break;;
[Nn]*) echo "Lets Start Over" 'restart script code goes here';;
[Aa]*) exit 0;;
*) echo "Try again";;
esac
done
echo
echo "Starting $build download for $opt1 from Jenkins"
echo
while true;do
read -p "Do you want to download something else? " yesno
case $yesno in
[Yy]* ) 'restart script code goes here';;
[Nn]* ) break;;
* ) echo "Try Again "
esac
done
If you design your shell script with shell functions, repeating a chunk of code gets much easier:
main() {
while true; do
next
if ! validate_opt 'Do you want to download something else?'; then
break
fi
done
}
validate_opt() {
local PS3="$1 (Press ctrl-c to exit) "
local choice
select choice in yes no; do
# This can be written more tersely,
# but for clarity...
case $choice in
yes) return 0;;
no) return 1;;
esac
done
}
do_download() {
echo
echo "Starting $build download for $opt1 from Jenkins"
echo
fetch "$1" # or whatever
}
next() {
if validate_opt 'Is this correct?'; then
do_download "$opt"
else
echo "Let's start over"
fi
}
main
function stage1 {
while true;do
read -p "Is this correct? (yes/no/abort) " yno
case $yno in
[Yy]*) stage2;;
[Nn]*) continue;;
[Aa]*) exit 0;;
*) echo "Try again";;
esac
done
}
function stage2 {
echo
echo "Starting $build download for $opt1 from Jenkins"
echo
while true;do
read -p "Do you want to download something else? " yesno
case $yesno in
[Yy]* ) stage1;;
[Nn]* ) exit 0;;
* ) echo "Try Again ";;
esac
done
}
stage1
You can do this using functions
The first function is stage 1 and the second stage2
After listing all the functions, at the bottom of the file we call stage1.
when the function stage1 executes and $yno= Y* or y* , it will skip to the stage2 function, vice versa when we in stage2

Infinite loop on yes/no ksh

I have an annoying issue that seems to cause and infinite loop and I can't work out why. If I call the following function, it keeps repeating the yes/no options infinitely down the screen until I crash out.
AuditUpload() {
clear
echo "Audit report generated successfully"
echo " "
echo "Do you wish to upload qhub_audit.csv? (1 = Yes/2 = No):"
sleep 1
select yn in "Yes" "No"; do
case $yn in
Yes ) AuditUploader; Auditvi; exit;;
No ) echo "Upload cancelled"; Auditvi; exit;;
esac
done
}
I put the sleep in to see if it would remedy the issue but it still does the same. This issue seems to be very intermittent and doesn't happen every time. This script is written in korn shell (ksh).
AuditUploader function:
AuditUploader() {
echo "Uploading qhub_audit.csv to $HOST..."
curl -v -T qhub_audit.csv -# ftp://xxxxxxxx:xxxxxxxxx#xxxxxxxxxxxxx.com/
if [ "$?" -ne "0" ]
then
echo "ERROR: Cannot upload qhubload.csv"
exit
else
clear
echo "qhub_audit.csv has been put on $HOST successfully"
tput cup 5 5
echo "Copy and paste this link into internet explorer to download:"
tput cup 7 5
echo "ftp://xxxxxxxx:xxxxxxxxx#xxxxxxxxxxxxx.com/qhub_audit.csv"
read LINK
fi
}
Auditvi function:
Auditvi() {
clear
echo "Do you wish to view qhub_audit.csv? (1 = Yes/2 = No):"
sleep 1
select yn in "Yes" "No"; do
case $yn in
Yes ) vi qhub_audit.csv; exit;;
No ) exit;;
esac
done
}
After a bit of playing around it looks like it was looping whenever the 'curl' command returned a specific error which stopped the kill $$ from working properly. I replaced kill $$ with exit 1 and amended the other functions accordingly. I also put in a contingency to use kermit in case the FTP failed. Anyway, this is what my code looks like now:
#########################################
# Upload quotehub audit report function #
#########################################
AuditUploader() {
echo "Uploading qhub_audit.csv to $HOST..."
curl -v -T qhub_audit.csv -# ftp://$USER:$PASSWD#$HOST/ -m 10
if [ "$?" -ne "0" ]
then
echo "ERROR: Cannot upload qhubload.csv via FTP"
if [ ${term} = "tty1A" ]
then
echo "Attempting to download to modems server..."
wermit -s qhub_audit.csv
if [ $? -ne 0 ]
then
echo "Cannot upload to modems either!"
echo "This file will have to be downloaded manually"
exit 1
else
clear
echo "qhub_audit.csv has been put on modems server successfully"
tput cup 5 5
echo "Copy and paste this link into START -> RUN to download:"
tput cup 7 5
echo "\\\\\\xxxxxxxx\download\general\qhub_audit.csv"
read LINK
fi
else
echo "Upload failed!"
exit 1
fi
else
clear
echo "qhub_audit.csv has been put on $HOST successfully"
tput cup 5 5
echo "Copy and paste this link into internet explorer to download:"
tput cup 7 5
echo "ftp://$USER:$PASSWD#$HOST/qhub_audit.csv"
read LINK
fi
}
#######################################################
# Function to prompt user to upload qhub audit report #
#######################################################
AuditUpload() {
clear
echo "Audit report generated successfully"
echo ""
echo "Do you wish to upload qhub_audit.csv? (y/n):"
read REPLY
case "$REPLY" in
Y) AuditUploader; Auditvi; exit;;
y) AuditUploader; Auditvi; exit;;
N) Auditvi; exit;;
n) Auditvi; exit;;
*) echo "invalid option";;
esac
}
######################################
# Function to view qhub audit report #
######################################
Auditvi() {
if [ "$?" -ne "0" ]
then
exit 1
else
clear
echo "Do you wish to view qhub_audit.csv? (y/n):"
read REPLY
case "$REPLY" in
Y) vi qhub_audit.csv; exit;;
y) vi qhub_audit.csv; exit;;
N) exit;;
n) exit;;
*) echo "invalid option"; Pause; Auditvi;;
esac
fi
}
Thanks again guys for all your help.

Shell Script with If, Select and Case

Can anyone advise how to edit this script to perform the following:
If folder exists - "then are you sure you want to uninstall?"
If yes - perform file copying, if not then stop script.
Else - can't find folder, stop script.
if [ -e "/tmp/installpackage" ]
then
echo "Are you sure you want to uninstall?"
select yn in "Yes" "No"; do
case $yn in
Yes )
echo "Beginning uninstall...";
cp file1.txt original/path/location;
break;;
No )
echo "Stopping uninstall.";
exit 1;;
esac
done
else
echo "Can't find the folder, package not isntalled."
exit 1
fi
Your code works as expected. But you have to enter 1 or 2 and not yes or no.
However I would change the first line to:
if [ -d "/tmp/installpackage" ]
-d tests whether the file exists and is a directory
I think after the line esac you want a exit otherwise you have a infinite loop to ask you for answers
try
if [ -d "/tmp/installpackage" ]
then
echo "Are you sure you want to uninstall?"
select yn in "Yes" "No"; do
case $REPLY in
Yes )
echo "Beginning uninstall...";
cp file1.txt original/path/location;
break;;
No )
echo "Stopping uninstall.";
exit 1;;
*)
echo "Incorrect choice";
break;;
esac
done
else
echo "Can't find the folder, package not installed."
exit 1
fi
I would try testing for bail out conditions first then fall through to the uninstall code:
[ ! -d '/tmp/installpackage' ] && \
echo "Can't find the folder, package not isntalled." && exit 1
echo -n 'Are you sure you want to uninstall? [y|n] '
read answer
[[ ! "$answer" = [Yy] ]] && echo 'Stopping uninstall.' && exit 1
echo 'Beginning uninstall...'
cp file1.txt original/path/location

I need to edit the bash script to select a letter to do separate commands

I am not sure what step is next in the process to get the commands to do what I want. I want to select a letter to do a command. Right now it lets you use any letter.
#!/bin/bash
echo "Please select l to list files of a directory, b to backup a file or directory, u to edit a user's password, and x to exit the script"
read $answer
if [ $answer="l" ]; then
printf "Please select folder:\n"
select d in */; do test -n "$d" && break; echo ">>> Invalid Selection"; done
cd "$d" && pwd
ls
fi
Use a case statement
case expression in
pattern1 )
statements ;;
pattern2 )
statements ;;
...
esac
e.g:
case $arg in
l)
printf "Please select folder:\n"
select d in */; do test -n "$d" && break; echo ">>> Invalid Selection"; done
cd "$d" && pwd
ls
;;
cmd1)
echo "Some other cmds line 1"
echo "Some other cmds line 2"
;;
-q) exit;;
*) echo "I'm the fall thru default";;
esac
You can use the select builtin for this, which will let you use numbers for each option instead of letters, but will take care of reading and validating input:
select cmd in \
"List files of a directory" \
"Backup a file or directory" \
"Edit a user's password" \
"Exit";
do
case $cmd in
1) do_list_files ;;
2) do_backup_files ;;
3) do_edit_password ;;
4) exit 0 ;;
esac
done
You can change the prompt by setting the PS3 variable (e.g. PS3="Your choice? ")

Resources