another unexpected token `fi' error - bash

I am trying to test 7 days for specific conditions and need to account for leap years. I think I have the logic right, been over it 100 times. But for some reason I keep getting the same error.
:~$ bin/shabbat/test
bin/shabbat/test: line 90: syntax error near unexpected token `fi'
bin/shabbat/test: line 90: ` fi'
Don't laugh to hard please. I am not a programmer. I have to copy/paste code that works and change it try to get it to do what I want it to do.
#!/bin/bash
STORDIR="${HOME}/bin/shabbat/data"
DAY=28
MONTH=1
YEAR=2016
# Calculate next day accounting for leap years
function Next_Day
{
case ${ $MONTH } in
1)
FULL="31"
;;
2)
FULL="28"
;;
3)
FULL="31"
;;
4)
FULL="30"
;;
5)
FULL="31"
;;
6)
FULL="30"
;;
7)
FULL="31"
;;
8)
FULL="31"
;;
9)
FULL="30"
;;
10)
FULL="31"
;;
11)
FULL="30"
;;
12)
FULL="31"
;;
esac
if [[ "$DAY" -le "27" ]]; then
(( DAY++ ))
exit
elif [[ ${MONTH} == "2" ]]; then
rem1=$((YEAR%4))
rem2=$((YEAR%100))
rem3=$((YEAR%400))
if [ ${rem3} = "0" ]; then
$FULL="29"
exit
fi
if [ ${rem2} = "0" -a ${rem3} != "0" ]; then
# echo "$YEAR Is Not A Leap Year"
exit
fi
if [ ${rem1} = "0" -a ${rem2} != "0" ]; then
# echo "$YEAR Is A Leap Year"
$FULL="29"
else
# echo "$YEAR Is Not A Leap Year"
exit
fi
if [ ${DAY} = ${FULL} -a ${MONTH} -lt "12" ]; then
(( MONTH++ ))
(( DAY++ ))
exit
fi
elif [ ${DAY} = ${FULL} -a ${MONTH} = "12" ]; then
(( YEAR++ ))
let MONTH=1
let DAY=1
exit
fi
exit
fi
}
#################
# # Main Code # #
#################
for (( i = 1; i < 7; i++)); do
YOMTOVE=$(hdate -dhq $DAY $MONTH $YEAR | awk 'NR==3')
echo "$YOMTOVE"
if [[ -n "$YOMTOVE" ]]; then
grep ^"$YOMTOVE" "$STORDIR"/YomTove.cvs
# actions based on what holiday it is
fi
done
Next_Day
exit
I have only gotten this far with help from my local lug and linuxquestion.org but I hate to keep bugging them with my old brain problems.
Thanks.

You either want to remove line 88 or line 90, they are unmatched fis. I am guessing you need to remove line 90.
Also I think you need to replace case ${ $MONTH } in with case ${MONTH} in

Related

How can I prevent and optimize a bad variable name?

When I run the code the output is ./fib.sh: 43: read: 6: bad variable name. What does it mean and how do I fix it?
case $# in
0)
echo "plz insert 3 integer number \n" && read a b n;;
1)a=$1 && echo "plz insert 2 integer number\n " && read b n ;;
2) a=$1 b=$2 && echo "plz insert 1 intger number \n" && read n ;;
3)a=$1 b=$2 n=$3 ;;
*)echo "The number of arguments is more than 3\n" && exit 1 ;;
esac
echo " a=$a b=$b n=$n\n"
while true ; do
if [ $n -eq 0 ] ;then
echo $a
elif [ $n -eq 1 ];then
echo $b
elif [ $n -ge 2 ] ; then
printf "%s ""$a"
printf "%s ""$b"
count=1
c=`expr $n - 1`
while [ $count -le $c ] ; do
printf "%s ""$answer"
answer=`expr $a + $b`
a=$b
b=$answer
count=`expr $count + 1`
done
echo "\nDo you want to try another n (yes/no):\n"
read s
case $s in
yes) echo"\nenter new value of n \n" && read $n && continue ;;
no) echo "Thank you" && exit 1 ;;
esac
fi
done
read: 6: bad variable name.
read $n expands the value of the variable n which, in this case, is 6. So that's read 6 trying to read into the variable 6. 6 is not a valid variable name in shell.
From context, you want to read into n which is read n.
yes) echo"\nenter new value of n \n" && read n && continue ;;

from the shellscript one option has been chosen OR none of them

am not expert on bash script and am looking help on. I would like to find a way at the end from the while loop condition that the script can be executed unless one option ([-1|-2|-3]) has been chosen OR none of them.
What the best way to do? I have absolutely no idea how to.
Many Thanks.
#!/bin/bash
echo " $0 [-e <option_e>] [-f <option_f>] [-1|-2|-3] [user#]fqdn"
OPTION1=""
OPTION2=""
OPTION3=""
while (( "$#" )); do
if [ "$1" == "-1" ]; then
OPTION1=1
elif [ "$1" == "-2" ]; then
OPTION2=1
elif [ "$1" == "-3" ]; then
OPTION3=1
fi
shift
done
I forgot to mention. this is a part of the script. further, there are several conditions that can conflict if there more then 2 options chosen.
EDIT: the valid selections either exactly one option or zero, but not two or more!
thank you SamuelKirschner -
I did to add [[ -n $ALL_OPTS ]] && then it works ! I am happy now.
#!/bin/bash
OPTION1=""
OPTION2=""
OPTION3=""
while (( "$#" )); do
if [ "$1" == "-1" ]; then
OPTION1=1
elif [ "$1" == "-2" ]; then
OPTION2=1
elif [ "$1" == "-3" ]; then
OPTION3=1
fi
shift
done
ALL_OPTS="$OPTION1$OPTION2$OPTION3";
echo $ALL_OPTS
if [[ -n $ALL_OPTS ]] && [[ $ALL_OPTS -ge 2 ]];then
echo 'Please provide a maximum of one of the options [-1|-2|-3]' 1>&2
exit 1
fi
You can simply test if all of the OPTION-variables concated have the wrong length with ALL_OPTS="$OPTION1$OPTION2$OPTION3"; test ${#ALL_OPTS} -ge 2 and exit. Where "$OPTION1$OPTION2$OPTION3" is just all of the variables written next to each other, therefor it is "", "1", "11" or "111".
#!/bin/bash
echo " $0 [-e <option_e>] [-f <option_f>] [-1|-2|-3] [user#]fqdn"
OPTION1=""
OPTION2=""
OPTION3=""
while (( "$#" )); do
if [ "$1" == "-1" ]; then
OPTION1=1
elif [ "$1" == "-2" ]; then
OPTION2=1
elif [ "$1" == "-3" ]; then
OPTION3=1
fi
shift
done
ALL_OPTS="$OPTION1$OPTION2$OPTION3";
if test ${#ALL_OPTS} -ge 2; then
echo 'Please provide a maximum of one of the options [-1|-2|-3]' 1>&2
exit 1
fi
From man bash
${#parameter}
Parameter length. The length in characters of the value of parameter is substituted. [...]
Edit: I messed up the condition quite a bit. (original answer was test -z "$OPTION1$OPTION2$OPTION3")
Keeping a count of options might be a possibility. Something like this, using getopts:
#!/usr/bin/env bash
echo "${0##*/} [-e <option_e>] [-f <option_f>] [-1|-2|-3] [user#]fqdn"
count=0
while getopts e:f:123 opt; do
case "$opt" in
e) opt_e="$OPTARG" ;;
f) opt_f="$OPTARG" ;;
1|2|3) declare opt_$opt=true; ((count++)) ;;
esac
done
shift $((OPTIND-1))
# Fail if our counter is too high
((count>1)) && printf 'ERROR: only one digit option allowed.\n' >&2 && exit 1
echo "done"
Alternately, you could keep the numeric options in a variable which you could check using globs:
#!/usr/bin/env bash
echo "${0##*/} [-e <option_e>] [-f <option_f>] [-1|-2|-3] [user#]fqdn"
nopt=""
while getopts e:f:123 opt; do
case "$opt" in
e|f) declare opt_$opt="$OPTARG" ;;
1|2|3) nopt="$nopt$opt" ;;
esac
done
shift $((OPTIND-1))
# Fail if we collected too many digits
((${#nopt}>1)) && printf 'ERROR: only one digit option allowed.\n' >&2 && exit 1
echo "done"
Then, you could switch functionality based on the value of $nopt.

Loop Script throws 0 by executing touch

I'm writing a script that makes a while loop for me, that I doesn't have to write a one line while loop again and again.
Short explanation:
The command "loop" will execute the command parameter -n times and with -p seconds pause. You can use -e to echo the command and not execute it. -v to show all parameters. Additionally its possible to use the iterator of the while loop.
Playing around with it, I've found a bug.
loop --verbose --times 5 'touch testfile$i'
#loop the touch command 5 times and generate the testfiles 0 to 4
same as:
loop -v -n 5 'touch testfile$i'
It generate "testfile0" to "testfile4" but also a file named "0"
Do somebody know why the file "0" will be generated?
And what do you think about a command like that? Would you like to use it?
Best
Steven
#!/bin/bash
# easy to use loop command
#
# Autor: Steven Wagner
# Date: 22 June 2018
# Version: 0.1
TIMES=0
FREQUENCY=0
PAUSE="0"
VERBOSE=false
ECHOONLY=false
SILENCE=false
POSITIONAL=()
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
-n|--times)
temp="$2"
if [[ $temp =~ ^[[:digit:]]+$ ]];
then
TIMES=$temp
else
echo "ERROR: value is not a digit"
exit
fi
shift # past argument
shift # past value
;;
-p|--pause)
#PAUSE="$2"
temp="$2"
PAUSE=$temp
#if [[ $temp =~ ^[[:digit:]]+$ ]];
#then
# PAUSE=$temp
#else
# echo "ERROR: value is not a digit"
# exit
#fi
shift # past argument
shift # past value
;;
-v|--verbose)
VERBOSE=true
shift # past argument
;;
-e|--echo-only)
ECHOONLY=true
shift # past argument
;;
-s|--silence)
SILENCE=true
shift # past argument
;;
--*)
echo "Error \"$key\" not known"
shift #past argument
;;
-*)
i=0
while [[ $i -lt ${#key}-1 ]]
do
char=${key:$[$i+1]:1}
case $char in
v)
VERBOSE=true
;;
e)
ECHOONLY=true
;;
s)
SILENCE=true
;;
esac
(( i++ ))
done
shift # past argument
;;
*) # unknown option
POSITIONAL+=("$1") # save it in an array for later
shift # past argument
;;
esac
done
set -- "${POSITIONAL[#]}" # restore positional parameters
#Pause make sleep command
pause=""
if [ $PAUSE > 0 ]
then
pause="sleep $PAUSE"
fi
#times make while control-command
times=""
if [ $TIMES != 0 ]
then
times="[ \$i -lt \$TIMES ]"
else
times="true" #infinity loop
fi
#Echo Only
command=$#
if $ECHOONLY
then
command="echo $#"
fi
#Silence
silence=""
if $SILENCE && ! $ECHOONLY
then
silence="&>/dev/null"
fi
if $VERBOSE
then
echo "pause = $PAUSE"
if [ $TIMES != 0 ]
then
echo "times = $TIMES"
else
echo "times = infinity"
fi
if $ECHOONLY; then echo "echo only = yes"; fi
if $SILENCE; then echo "silence = yes"; fi
echo "command = '$#' $silence"
echo
fi
#start the loop
timestamp=$(date +%s%N)
eval "
i=0
while $times
do
eval '$command' $silence
$pause
(( i++ ))
done
"
if $VERBOSE
then
echo
echo "duration: $[($(date +%s%N)-$timestamp)/1000000]ms"
fi

comparing $var to

I have a test script the needs to read the variable 'LAB' and e-mail the correct company.
I've looked but can't find anything that has worked yet.
Any thoughts?
#!
#
LAB=3
#
if [ "$LAB" = "$1" ];then
echo "Got Zumbrota" && ./mailZ
fi
#
if [ "$LAB" = "$2" ];then
echo "Got Barron" && ./mailB
fi
#
if [ "$LAB" = "$3" ];then
echo "Got Stearns" && ./mailS
fi
If this a bash script, start your file with
#!/bin/bash
and use -eq for integer comparison and since LAB is an integer in your script
if [ $LAB -eq $1 ]
These cascading if statements can be condensed into a case statement:
case "$LAB" in
1) echo "Got Zumbrota" && ./mailZ
;;
2) echo "Got Barron" && ./mailB
;;
3) echo "Got Stearns" && ./mailS
;;
*) echo "don't know what to do with $LAB"
;;
esac

Creating a calculator script

I am trying to make a calculator with a bash script.
The user enters a number, chooses whether they wish to add, subtract, multiply or divide. Then the user enters a second number and is able to choose whether to do the sum, or add, subtract, multiply or divide again on a loop.
I cannot rack my head around this right now
echo Please enter a number
read number
echo What operation would you like to perform: 1: Add, 2: Subtract, 3: Multiple, 4: Divide
read operation
case $operation in
1) math='+';;
2) math='-';;
3) math='*';;
4) math='/';;
*) math='not an option, please select again';;
esac
echo "$number $math"
echo Please enter a number
read number2
echo What operation would you like to perform: 1: Add, 2: Subtract, 3: Multiple, 4: Divide, 5: Equals
read operation2
case $operation2 in
1)math2='Add';;
2)math2='Subtract';;
3)math2='Multiply';;
4)math2='Divide';;
5)math2='Equals';;
*)math2='not an option, please select again';;
esac
echo You have selected $math2
exit 0
This is what I have done so far, but can anyone help me work out how to loop back on the calculator?
The lesser-known shell builtin command select is handy for this kind of menu-driven program:
#!/bin/bash
while true; do
read -p "what's the first number? " n1
read -p "what's the second number? " n2
PS3="what's the operation? "
select ans in add subtract multiply divide; do
case $ans in
add) op='+' ; break ;;
subtract) op='-' ; break ;;
multiply) op='*' ; break ;;
divide) op='/' ; break ;;
*) echo "invalid response" ;;
esac
done
ans=$(echo "$n1 $op $n2" | bc -l)
printf "%s %s %s = %s\n\n" "$n1" "$op" "$n2" "$ans"
done
Sample output
what's the first number? 5
what's the second number? 4
1) add
2) subtract
3) multiply
4) divide
what's the operation? /
invalid response
what's the operation? 4
5 / 4 = 1.25000000000000000000
If I was going to get fancy with bash v4 features and DRY:
#!/bin/bash
PS3="what's the operation? "
declare -A op=([add]='+' [subtract]='-' [multiply]='*' [divide]='/')
while true; do
read -p "what's the first number? " n1
read -p "what's the second number? " n2
select ans in "${!op[#]}"; do
for key in "${!op[#]}"; do
[[ $REPLY == $key ]] && ans=$REPLY
[[ $ans == $key ]] && break 2
done
echo "invalid response"
done
formula="$n1 ${op[$ans]} $n2"
printf "%s = %s\n\n" "$formula" "$(bc -l <<< "$formula")"
done
Wrapping Code in a Loop
If you just want to wrap your code in a Bash looping construct, and are willing to hit CTRL-C to terminate the loop rather than do something more fancy, then you can wrap your code in a while-loop. For example:
while true; do
: # Your code goes here, inside the loop.
done
Just make sure to move your unconditional exit statement out of the body of the loop. Otherwise, the loop will terminate whenever it reaches that line.
For your ~/.bashrc:
alias bc="BC_ENV_ARGS=<(echo "scale=2") \bc"
Just use bc, with that alias it automatically works with two decimals instead of integers.
!/bin/bash
PS3="what's the operation? "
declare -A op=([add]='+' [subtract]='-' [multiply]='*' [divide]='/')
while true; do
read -p "what's the first number? " n1
read -p "what's the second number? " n2
select ans in "${!op[#]}"; do
for key in "${!op[#]}"; do
[[ $REPLY == $key ]] && ans=$REPLY
[[ $ans == $key ]] && break 2
done
echo "invalid response"
done
formula="$n1 ${op[$ans]} $n2"
printf "%s = %s\n\n" "$formula" "$(bc -l <<< "$formula")"
done
Please use the following script.
clear
sum=0
i="y"
echo " Enter one no."
read n1
echo "Enter second no."
read n2
while [ $i = "y" ]
do
echo "1.Addition"
echo "2.Subtraction"
echo "3.Multiplication"
echo "4.Division"
echo "Enter your choice"
read ch
case $ch in
1)sum=`expr $n1 + $n2`
echo "Sum ="$sum;;
2)sum=`expr $n1 - $n2`
echo "Sub = "$sum;;
3)sum=`expr $n1 \* $n2`
echo "Mul = "$sum;;
4)sum=`expr $n1 / $n2`
echo "Div = "$sum;;
*)echo "Invalid choice";;
esac
echo "Do u want to continue ?"
read i
if [ $i != "y" ]
then
exit
fi
done
#calculator
while (true) # while loop 1
do
echo "enter first no"
read fno
if [ $fno -eq $fno 2>/dev/null ]; # if cond 1 -> checking integer or not
then
c=1
else
echo "please enter an integer"
c=0
fi # end of if 1
if [ $c -eq 1 ]; #if 2
then
break
fi # end of if 2
done # end of whie 1
while(true) #while loop 2
do
echo "enter second no"
read sno
if [ $sno -eq $sno >/dev/null 2>&1 ] # if cond 3 -> checking integer or not
then
c=1
else
echo "please enter an integer"
c=0
fi # end of if 3
if [ $c -eq 1 ] # if cond 4
then
break
fi # end of if 4
done #2
while(true) # while loop 3
do
printf "enter the operation (add,div,mul,sub) of $fno and $sno\n"
read op
count=0
##addition
if [ $op = add ] #if cond 5
then
echo "$fno+$sno is `expr $fno + $sno`"
#multiplication
elif [ $op = mul ];
then
echo "$fno*$sno is `expr $fno \* $sno`"
#substraction
elif [ $op = sub ]
then
while(true) #while loop 3.1
do
printf "what do you want to do??? \n 1. $fno-$sno \n 2. $sno-$fno"
printf "\n press the option you want to perform?(1 or 2)\n"
read opt
if [ $opt = 1 ] #if cond 5.1
then
echo "$fno-$sno is `expr $fno - $sno`"
break
elif [ $opt = 2 ]
then
echo " $sno-$fno is `expr $sno - $fno`"
break
else "please enter valid options to proceed(1 or 2)";
clear
fi #end of if 5.1
done # end of 3.1
#division
elif [ $op = div ]
then
while(true) # whilw loop 3.2
do
printf "what do you want to do??? \n 1. $fno/$sno \n 2. $sno/$fno"
printf "\n press the option you want to perform?(1 or 2)\n"
read opt
if [ $opt = 1 ] #if cond 5.2
then
echo "$fno divided by $sno is `expr $fno / $sno`"
break
elif [ $opt = 2 ]
then
echo " $sno divided by $fno is `expr $sno / $fno`"
break
else
clear
fi #end of if 5.2
done # end of 3.2
else
echo "valid option please!!!"
count=1
fi # end of if 5
if [ $count -eq 0 ] #if cond 6
then
echo "Do you want to do more ops"
echo "(y/n)"
read ans
clear
if [ $ans = n ] # if 6.1
then
break
fi # end of if 6.1
fi #end of if 6
done #end of while 3

Resources