How do I find the middle of three numbers in shell script - bash

#!/bin/bash
echo "Enter three numbers and this program will give you the middle number : " ; read num1 ; read num2 ; read num3
if [ "$num1" -gt "$num2" ] && [ "$num1" -lt "$num3" ] || [ "$num1" -lt "$num2" ] && [ "$num1" -gt "$num3" ]; then
{
echo "The middle number is $num1"
}
elif [ "$num2" -gt "$num1" ] && [ "$num2" -lt "$num3" ] || [ "$num2" -lt "$num1" ] && [ "$num2" -gt "$num3" ]; then
{
echo "The middle number is $num2"
}
elif [ "$num3" -gt "$num1" ] && [ "$num3" -lt "$num2" ] || [ "$num3 -lt "$num1" ] && [ "$num3" -gt "$num2" ]; then
{ echo "The middle number is $num3" }
fi
The problem I have is with the or condition. I input the numbers 1, 2, and 3, but I get the middle number as 1 all the time.

How about this:
getmid() {
if (( $1 <= $2 )); then
(( $1 >= $3 )) && { echo $1; return; }
(( $2 <= $3 )) && { echo $2; return; }
fi;
if (( $1 >= $2 )); then
(( $1 <= $3 )) && { echo $1; return; }
(( $2 >= $3 )) && { echo $2; return; }
fi;
echo $3;
}
# All permutations of 1, 2 and 3 print 2.
getmid 1 2 3
getmid 2 1 3
getmid 1 3 2
getmid 3 1 2
getmid 2 3 1
getmid 3 2 1

This one should work:
#!/bin/bash
echo "Enter three numbers and this program will give you the middle number : " ; read num1 ; read num2 ; read num3;
if [ "$num1" -gt "$num2" ] && [ "$num1" -lt "$num3" ]; then
{
echo "The middle number is" $num1 ;
}
elif [ "$num1" -lt "$num2" ] && [ "$num1" -gt "$num3" ]; then
{
echo "The middle number is" $num1 ;
}
elif [ "$num2" -gt "$num1" ] && [ "$num2" -lt "$num3" ]; then
{
echo "The middle number is" $num2 ;
}
elif [ "$num2" -lt "$num1" ] && [ "$num2" -gt "$num3" ]; then
{
echo "The middle number is" $num2 ;
}
elif [ "$num3" -gt "$num1" ] && [ "$num3" -lt "$num2" ]; then
{
echo "The middle number is" $num3 ;
}
elif [ "$num3" -lt "$num1" ] && [ "$num3" -gt "$num2" ]; then
{
echo "The middle number is" $num3 ;
}
fi

Related

I'm using this shell script to identify the maximum and minimum of the performed arithmetic operation but facing issue with float value in if block

read -p "enter first number : " a
read -p "enter second number : " b
read -p "enter third number : " c
if [ $b -gt 0 ]
then
w=`echo $a $b $c | awk '{print $1+$2*$3}'`;
echo $w;
x=`echo $a $b $c | awk '{print $1%$2+$3}'`
echo $x
y=`echo $c $a $b | awk '{print $1+$2/$3}'`
echo $y
z=`echo $a $b $c | awk '{print $1*$2+$3}'`
echo $z
if [ $w -gt $x ] && [ "($w -gt $y | bc)" ] && [ $w -gt $z ]
then
echo $w"w"
elif [ $x -gt $w ] && [ "( $x -gt $y | bc )" ] && [ $x -gt $z ]
then
echo $x"x"
elif [ $z -gt $w ] && [ $z -gt $x ] && [ "($z -gt $y | bc)" ]
then
echo $z"z"
else
echo $y"y"
fi
if [ $w -lt $x ] && [ "( $w -lt $y | bc )" ] && [ $w -lt $z ]
then
echo $w"w"
elif [ $x -lt $w ] && [ "( $x -lt $y | bc )" ] && [ $x -lt $z ]
then
echo $x"x"
elif [ $z -lt $w ] && [ $z -lt $x ] && [ "($z -lt $y | bc )" ]
then
echo $y"y"
else
echo $z"z"
fi
fi

Values of an array not comparing to numbers correctly

Im trying to get an array from grades.txt, and determine what letter grade it should be assigned.
I either get
hw4part2.sh: line 26: [: : integer expression expected
If i use -ge or
hw4part2.sh: line 26: [: : unary operator expected
If i use >=
Below is the code im trying to get working
mapfile -t scores < grades.txt
numOScores=0
numOA=0
numOB=0
numOC=0
numOD=0
numOF=0
DoneWScores=0
A=90
B=80
C=70
D=60
F=59
while [ $DoneWScores -eq 0 ]
do
numOScores=$((numOScores + 1))
if [ "${scores[$numOScores]}" -ge "$A" ]
then
echo "A"
elif [ "${scores[$numOScores]}" -ge "$B" ]
then
echo "B"
elif [ "${scores[$numOScores]}" -ge "$C" ]
then
echo "C"
elif [ "${scores[$numOScores]}" -ge "$D" ]
then
echo "D"
elif [ "${scores[$numOScores]}" -le "$F" ]
then
echo "F"
else
echo "Done/error"
DoneWScores=1
fi
done
If anyone knows what my problem is, that'd be greatly appreciated
Consider this:
#!/usr/bin/env bash
if (( ${BASH_VERSINFO[0]} < 4 )); then
echo "Bash version 4+ is required. This is $BASH_VERSION" >&2
exit 1
fi
letterGrade() {
if (( $1 >= 90 )); then echo A
elif (( $1 >= 80 )); then echo B
elif (( $1 >= 70 )); then echo C
elif (( $1 >= 60 )); then echo D
else echo F
fi
}
declare -A num
while read -r score; do
if [[ $score == +([[:digit:]]) ]]; then
grade=$(letterGrade "$score")
(( num[$grade]++ ))
echo "$grade"
else
printf "invalid score: %q\n" "$score"
fi
done < grades.txt
for grade in "${!num[#]}"; do
echo "$grade: ${num[$grade]}"
done | sort

Shell : logical ANDs and ORs instead of if-else

I was wondering why
i=10
if [ $i -lt 5 ]; then
echo "$i < 5"
elif [ $i -gt 5 ]; then
echo "$i > 5"
elif [ $i -eq 5 ]; then
echo "$i = 5"
fi
Outputs proper result:
10 > 5
Whereas
i=10
[ $i -lt 5 ] && {
echo "$i < 5"
} || [ $i -gt 5 ] && {
echo "$i > 5"
} || [ $i -eq 5 ] && {
echo "$i = 5"
}
behaves an unusual way:
10 > 5
10 = 5
In my opinion, as the interpreter seeks for 1s, it should work like this:
0 && {} || 1 && {} || 0 && {}
0 so the 0 && {} is definitely 0; skip {}
1 means that {} must be checked to define the value of whole 1 && {}
So that the result is 1, but the only {} is executed stays after 1.
However, this all does work as it should when I put ! { instead of {s.
i=10
[ $i -lt 5 ] && ! {
echo "$i < 5"
} || [ $i -gt 5 ] && ! {
echo "$i > 5"
} || [ $i -eq 5 ] && ! {
echo "$i = 5"
}
WHY?! I thought it seeks for 1s so since it finds a 0 in a && it doesn't look at other expressions in the chain!
The {...} does not make a difference, so what you have is equivalent to this:
i=10
[ $i -lt 5 ] &&
echo "$i < 5" ||
[ $i -gt 5 ] &&
echo "$i > 5" ||
[ $i -eq 5 ] &&
echo "$i = 5"
And the way this works is:
[ $i -lt 5 ]: This is false (returns failure), so it jumps to the next ||, which has [ $i -gt 5 ] following it.
[ $i -gt 5 ]: This is true (returns success), so it jumps to the next &&, which has echo "$i > 5" following it.
echo "$i > 5": This returns success, so it jumps to the next &&, which has echo "$i = 5" following it.
echo "$i = 5": This returns success, so it jumps to... wait no, there's a newline. We're done.
&& and || are called short-circuit operators.
EDIT: To stress the point further,
A && B || C
is NOT the same as
if A; then
B
else
C
fi
It's equivalent to
if A; then
if ! B; then
C
fi
else
C
fi
&& and || are evaluated from left to right. Your command is more or less equivalent to this:
(((( false && { echo 1; true; } ) || true ) && { echo 2; true; } ) || false ) && { echo 3; true; }
false && { echo 1; true; } doesn't print anything, and evaluates to false
false || true evaluates to true
true && { echo 2; true; } prints 2 and evaluates to true
true || false evaluates to true
true && { echo 3; true; } prints 3 and evaluates to true.
Mystery solved.

Inner If else statement in Shell Script

While i am executing following code, when if [ $c_count -eq $p_count ] get fails then control goes directly to outer else part. But it should go to inner else part.
What is issue in this...?
while [ "${arr2[$j]}" != "P" ]
do
if [ $j -ge $i ]
then
break
fi
if [ "${arr1[$j]}" == "M" -a $p_count -ne 0 ]
then
c_count=`grep -c "<${arr3[$j]}>" $2`
if [ $c_count -eq $p_count ]
then
echo "${arr1[$j]} ${arr2[$j]} Y $c_count ${arr3[$j]} >>>>>"
else
echo "${arr1[$j]} ${arr2[$j]} N $c_count ${arr3[$j]} "
mcinvalid=`expr $mcinvalid + 1`
echo "Count Incremented"
fi
else
c_count=`grep -c "<${arr3[$j]}>" $2`
echo "${arr1[$j]} ${arr2[$j]} N $c_count ${arr3[$j]} -------"
fi
j=`expr $j + 1`
done

BASH function: syntax error near unexpected token `'2''

I am completely lost as to why this error keeps happening, I am fairly certain that I am using the correct syntax, however, every time I execute this BASH script, I get the following error:
/home/clucky/MCServerBackup/MCServerBackup.sh: line 200: syntax error near unexpected token `'2''
/home/clucky/MCServerBackup/MCServerBackup.sh: line 200: ` logInfo() '2' "none" "Minecraft: $minecraftsize.$minecraftsized $minecraftunit"'
The line in particular that it appears to be refrencing is line 200, which is where the code attempts to execute the function logInfo() as follows:
logInfo() '2' "none" "Minecraft: $minecraftsize.$minecraftsized $minecraftunit"
In the above line of code, 2 is the indent level (2 x 5 spaces). none tells the function to ignore the logLevel that is specified in the configuration and log it anyway. Minecraft: $minecraftsize...$minecraftunit is what is being added into the log file, which the words preceeded by a $ are of course variables. The entire code can be viewed below.
#! /usr/bin/env bash
#Declare Functions
logInfo() {
if [ "$logInFile" == "true" ] || [ "$logInConsole" == "true" ] ; then
let tabAmount=5*$1
indent=""
for (( indentrepeat=0; indentrepeat < $tabAmount; indentrepeat++ ))
do
indent="$indent "
done
if [ "$2" == "none" ] ; then
infoItem="$3"
else
if [ "$logLevel" == "high" ] ; then
if [ "$2" == "subtask" ] ; then
#High + Subtask
infoItem="`date '+%H:%M:%S'` $3"
elif [ "$2" == "task" ] ; then
#High + Task
infoItem="`date '+%H:%M:%S'` $3"
fi
elif [ "$logLevel" == "medium" ] ; then
if [ "$2" == "subtask" ] ; then
#Medium + Subtask
infoItem="$3"
elif [ "$2" == "task" ] ; then
#Medium + Task
infoItem="`date '+%H:%M:%S'` $3"
fi
else
if [ "$2" == "subtask" ] ; then
#Low + Subtask
infoItem=''
elif [ "$2" == "task" ] ; then
#Low + Task
infoItem="$3"
fi
fi
fi
if [ "$logInFile" == "true" ] ; then
echo -e "$indent$infoItem" >> backup.log
fi
if [ "$logInConsole" == "true" ] ; then
echo -e "$indent$infoItem"
fi
fi
}
logError() {
if [ "$logInFile" == "true" ] || [ "$logInConsole" == "true" ] ; then
let tabAmount=5*$1
indent=""
for (( indentrepeat=0; indentrepeat < $tabAmount; indentrepeat++ ))
do
indent="$indent "
done
if [ "$logInFile" == "true" ] && [ "$logErrors" == "true" ] ; then
echo -e "$indent[ERROR] $2" >> backup.log
fi
if [ "$logInConsole" == "true" ] && [ "$logErrors" == "true" ] ; then
echo -e "$indent[ERROR] $2"
fi
fi
}
#Set Variables
source config.sh
minecraftsize=0
sqlsize=0
websitesize=0
timedate=`date '+%m.%d.%Y-%H:%M'`
#Update
if [ $version != "1.0.0" ] ; then
source update.sh
fi
#Trigger General Settings
echo -ne "\033]0;$serverName - Backup\007"
if [ "$serverDirectory" == "default" ] ; then
BINDIR="$(dirname "$(readlink -fn "$0")")"
cd "$BINDIR"
else
if [ -d "$serverDirectory" ] ; then
cd "$serverDirectory"
else
directoryExists=false
echo '$serverDirectory defined as '"$serverDirectory"' does not exist. Please double check your configuration and make sure this folder exists.'
if [ "$logInFile" == "true" ] ; then
echo "-------------- `date '+%d-%B-%Y %H:%M'` --------------" >> backup.log
echo -e ' [ERROR] $serverDirectory defined as '"$serverDirectory"', does not exist. Please double check your configuration and make sure this folder exists.'"\n" >> backup.log
fi
fi
fi
if [ "$purgeFiles" == "true" ] || [ "$backupMinecraft" == "true" ] || [ "$backupMySQL" == "true" ] || [ "$backupWebsite" == "true" ] && [ "$directoryExists" != "false" ] ; then
echo "-------------- `date '+%d-%B-%Y %H:%M'` --------------" >> backup.log
#Create Directories
echo "[`date '+%H:%M:%S'`] Directory Creation Started" >> backup.log
if [ ! -d ".backups" ] ; then
mkdir -p .backups
fi
mkdir -p .backups/$timedate
if [ "$backupMySQL" == "true" ] ; then
mkdir -p .backups/$timedate/MySQL
fi
if [ "$backupWebsite" == "true" ] ; then
mkdir -p .backups/$timedate/Website
fi
if [ "$backupMinecraft" == "true" ] ; then
mkdir -p .backups/$timedate/MinecraftServers
fi
echo "[`date '+%H:%M:%S'`] Directory Creation Completed" >> backup.log
#Backup Minecraft Servers
if [ "$backupMinecraft" == "true" ] ; then
echo "[`date '+%H:%M:%S'`] Minecraft Backup Started" >> backup.log
for (( servercount = 0; servercount < ${#mcservers[#]}; servercount++ ))
do
echo " ${mcservers[servercount]}" >> backup.log
tar -zcpf .backups/$timedate/MinecraftServers/${mcservers[servercount]}.tar.gz --directory ${mcservers[servercount]} ${fileexcludes[servercount]} .
minecraftsize=`expr $minecraftsize + $(ls -la .backups/$timedate/MinecraftServers/${mcservers[servercount]}.tar.gz | awk '{ print $5}')`
done
echo "[`date '+%H:%M:%S'`] Minecraft Backup Completed" >> backup.log
fi
#Copy MySQL Databases
if [ "$backupMySQL" == "true" ] ; then
echo "[`date '+%H:%M:%S'`] MySQL Backup Started" >> backup.log
for (( sqlcount = 0; sqlcount < ${#sqldatabases[#]}; sqlcount++ ))
do
if [[ "${sqldatabases[sqlcount]}" =~ # ]] ; then
sqldatabases[sqlcount]=${sqldatabases[sqlcount]//[#]/}
mysqldump -u"$sqluser" -p"$sqlpass" -h"$sqlhost" ${sqldatabases[sqlcount]} > .backups/$timedate/MySQL/${sqldatabases[sqlcount]}.sql;
sqlsize=`expr $sqlsize + $(ls -la .backups/$timedate/MySQL/${sqldatabases[sqlcount]}.sql | awk '{ print $5}')`
echo " ${sqldatabases[sqlcount]}*" >> backup.log
else
mysqldump -u"$sqluser" -p"$sqlpass" -h"$sqlhost" --skip-lock-tables ${sqldatabases[sqlcount]} > .backups/$timedate/MySQL/${sqldatabases[sqlcount]}.sql;
sqlsize=`expr $sqlsize + $(ls -la .backups/$timedate/MySQL/${sqldatabases[sqlcount]}.sql | awk '{ print $5}')`
echo " ${sqldatabases[sqlcount]}" >> backup.log;
fi
done
fi
#Backup Website
if [ "$backupWebsite" == "true" ] ; then
echo "[`date '+%H:%M:%S'`] Website Backup Started" >> backup.log
if [ "$websiteDirectory" == "default" ] ; then
websiteDirectory=var/www/
fi
if [ -d "$websiteDirectory" ] ; then
tar -zcpf .backups/$timedate/Website/website.tar.gz --directory $websiteDirectory $websiteExcludes .
echo "[`date '+%H:%M:%S'`] Website Backup Completed" >> backup.log
else
logError "5" "\0044websiteDirectory defined as $websiteDirectory does not exist. Please double check your configuration and make sure this folder exists."
echo "[`date '+%H:%M:%S'`] Website Backup Cancelled" >> backup.log
fi
fi
#Purge files 3 days old
if [ "$purgeFiles" == "true" ] ; then
echo "[`date '+%H:%M:%S'`] Purging Old Backups" >> backup.log
find .backups* -mmin +$purgeTime -exec rm --recursive {} \;
echo "[`date '+%H:%M:%S'`] Purging Complete" >> backup.log
fi
#Read back file size
let filesize=$minecraftsize+$sqlsize+$websitesize
if [ "$filesize" -ge 1024 ] ; then
if [ "$filesize" -ge 1048576 ] ; then
if [ "$filesize" -ge 1073741824 ] ; then
filedivider=1073741824
fileunit="GB"
else
filedivider=1048576
fileunit="MB"
fi
else
filedivider=1024
fileunit="KB"
fi
else
filedivider=1
fileunit="Bytes"
fi
let filesized='(''('$filesize%$filedivider')'*100')'/$filedivider
let filesize=$filesize/$filedivider
echo " Total Compression Size: $filesize.$filesized $fileunit" >> backup.log
if [ "$backupMinecraft" == "true" ] ; then
if [ "$minecraftsize" -ge 1024 ] ; then
if [ "$minecraftsize" -ge 1048576 ] ; then
if [ "$minecraftsize" -ge 1073741824 ] ; then
minecraftdivider=1073741824
minecraftunit="GB"
else
minecraftdivider=1048576
minecraftunit="MB"
fi
else
minecraftdivider=1024
minecraftunit="KB"
fi
else
minecraftdivider=1
minecraftunit="Bytes"
fi
let minecraftsized='(''('$minecraftsize%$minecraftdivider')'*100')'/$minecraftdivider
let minecraftsize=$minecraftsize/$minecraftdivider
logInfo() '2' "none" "Minecraft: $minecraftsize.$minecraftsized $minecraftunit"
fi
if [ "$backupMySQL" == "true" ] ; then
if [ "$sqlsize" -ge 1024 ] ; then
if [ "$sqlsize" -ge 1048576 ] ; then
if [ "$sqlsize" -ge 1073741824 ] ; then
sqldivider=1073741824
sqlunit="GB"
else
sqldivider=1048576
sqlunit="MB"
fi
else
sqldivider=1024
sqlunit="KB"
fi
else
sqldivider=1
sqlunit="Bytes"
fi
let sqlsized='(''('$sqlsize%$sqldivider')'*100')'/$sqldivider
let sqlsize=$sqlsize/$sqldivider
echo " MySQL: $sqlsize.$sqlsized $sqlunit" >> backup.log
fi
if [ "$backupWebsite" == "true" ] ; then
if [ "$websitesize" -ge 1024 ] ; then
if [ "$websitesize" -ge 1048576 ] ; then
if [ "$websitesize" -ge 1073741824 ] ; then
websitedivider=1073741824
websiteunit="GB"
else
websitedivider=1048576
websiteunit="MB"
fi
else
websitedivider=1024
websiteunit="KB"
fi
else
websitedivider=1
websiteunit="Bytes"
fi
let websitesized='(''('$websitesize%$websitedivider')'*100')'/$websitedivider
let websitesize=$websitesize/$websitedivider
echo " Website: $websitesize.$websitesized" >> backup.log
fi
echo "" >> backup.log
fi
As I stated earlier, I am completely lost, so any assistance would be greatly appreciated. Thank you!
You don't invoke a function with parentheses. Change:
logInfo() '2' "none" "Minecraft: $minecraftsize.$minecraftsized $minecraftunit"
to
logInfo '2' "none" "Minecraft: $minecraftsize.$minecraftsized $minecraftunit"

Resources