unix all if statements in one place - bash

I am newly learning shell script ! i tried following code but i have error
line 15: syntax error near unexpected token `elif
#!/bin/bash
read -p "Enter the number : " n
if [ $n -eq 1 ]
then
echo "$n is equal to 1 true"
elif [ $n -lt 4 ]
then
echo "$n is less than value of 4 ture"
else
echo "$n is not less then value of 4 false"
elif [ $n -gt 10 ]
then
echo "$n is greater than the value of 10 true"
else
echo "$n is not greater than the value of 10 false"
if [ $n -ge 0 ]
then
echo "$n is greater than or equal to 0"
else
echo "$n is not greater than or equal to 0"
fi
else
"Bye"
fi
Can anyone help ?

It's a bit hard to tell what your intention is. The correct answer depends on what you want to do here. My guess is that you want this:
if [ $n -eq 1 ]
then
echo "$n is equal to 1 true"
elif [ $n -lt 4 ]
then
echo "$n is less than value of 4 true"
elif [ $n -gt 10 ]
then
echo "$n is greater than the value of 10 true"
elif [ $n -ge 0 ]
then
# This will be true if $n is >= 4 and <= 10
echo "$n is greater than or equal to 0"
else
# Negative
"Bye"
fi

Related

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

Validating number of arguments

I apologize for the beginners question ahead of time but I cannot get this chunk of code to work properly. I was asked to make a basic program which asks the user for 3 numbers and then checks which is the highest value and prints the results, as well as makes sure there are three numbers put in. It can determine which is his highest and im getting it to output results properly but I cant seem to figure out how to get it to validate that there are three numbers put in.
I have done research and even pulled some code from the teachers example about how to check the number of arguments but I still cant get it to work.
#!/bin/bash
echo "Please enter three numbers:"
read a b c
if [ $# -ne 3 ]
then
echo "You need three numbers"
exit -1
fi
if [ $a -gt $b -a $a -gt $c ]
then
LARGEST=$a
elif [ $b -gt $a -a $b -gt $c ]
then
LARGEST=$b
elif [ $c -gt $a -a $c -gt $b ]
then
LARGEST=$c
elif [ $a -eq $b -a $a -eq $c -a $b -eq $c -eq $b ]
then
LARGEST="All three values are equal."
fi
echo "The largest values is $LARGEST"
When I enter three numbers (7 8 9) I expect to get back:
"The largest value is 9"
however I get this instead:
./values.sh: line 6 [0: command not found
The largest value is 9
Am i missing something blatantly obvious here? I know i need an operator to make my original if statement work but am i using the wrong one?
The [ -z "$c" ] test solves it for the code you posted.
Working code:
#!/bin/bash
echo "Please enter three numbers:"
read a b c d
if [ -z "$c" ]
then
echo "You need three numbers"
exit -1
fi
if [ -n "$d" ]
then
echo "enter only three numbers"
exit -1
fi
if [ $a -gt $b -a $a -gt $c ]
then
LARGEST=$a
elif [ $b -gt $a -a $b -gt $c ]
then
LARGEST=$b
elif [ $c -gt $a -a $c -gt $b ]
then
LARGEST=$c
elif [ $a -eq $b -a $a -eq $c -a $b -eq $c -eq $b ]
then
LARGEST="All three values are equal."
fi
echo "The largest values is $LARGEST"
Output:
$ ./t.sh
Please enter three numbers:
7 8
You need three numbers
$ ./t.sh
Please enter three numbers:
7 8 9
The largest values is 9

Bash; conditional statement echoing numbers

I'm nearly done writing a script for an assignment, but am having some trouble thinking of how to do this final part.
My problem is within a while loop; it prints out the number based on the IF statements, the number entered will always be an even number.
The IFs aren't connected by else/elif because the number should be able to printed out if it applies to more than 1 of the statements.
I want to print $starting on every loop if it doesn't meet any of the IF conditions, but if it does I don't want to print it. Can anyone see how to do that?
while [[ $starting -lt $ending ]]; do
if [ $((starting %7)) -eq 0 ]
then
echo "$starting red"
fi
if [ $((starting % 11)) -eq 0 ]
then
echo "$starting green"
fi
if [ $((starting % 13)) -eq 0 ]
then
echo "$starting blue"
fi
starting=$((starting + 2))
done
Keep track of whether you've done what you want to do in a variable:
while [[ $starting -lt $ending ]]; do
handled=0
if [ $((starting %7)) -eq 0 ]
then
echo "$starting red"
handled=1
fi
if [ $((starting % 11)) -eq 0 ]
then
echo "$starting green"
handled=1
fi
if [ $((starting % 13)) -eq 0 ]
then
echo "$starting blue"
handled=1
fi
if ! (( handled ))
then
echo "$starting didn't match anything"
fi
starting=$((starting + 2))
done
Add another if at the end that checks if none of the previous if statements are true. if !(starting%7==0 or starting%11==0 or starting%13==0) => echo starting

floating point value not working if the value is not manually assigned

I need to check if the percentage change is > 0, ==0, < 0, and NULL.
So I got get_count() that returns result of SELECT statement...:
get_count () {
sqlplus -s un/pass <<!
set heading off
set feedback off
set pages 0
select trunc(PRNCT_CHANGE, 3)
FROM SEMANTIC.COUNT_STATISTICS;
exit;
!
}
count=$(get_count $1) #possible values: -0.789, -10.999, 11.897, 20, 1, 0...
if [ -z "$count" ]; then
echo "The count percentage change returns null value"
elif [[ "$count" -gt 0 ]]; then
echo "The count percentage change ($count) is greater than zero"
elif [[ "$count" == 0 ]]; then
echo "The count percentage change stays unchanged (is zero)"
elif [[ "$count" =~ ^[\-0-9] ]]; then
echo "The count percentage change is $count"
else
echo "$count ... Something else is wrong here"
fi
If I manually assign value for $count ie:
count=-0.987
This is working great.
otherwise if I let get_count() method return the value, it is always jumping to else statement...
Should I convert the value that gets passed to $count variable somehow..?
bash doesn't understand floating point values. You'll need to use an external program like bc to do the comparison:
if [ -z "$count" ]; then
echo "The count percentage change returns null value"
elif [[ $(echo "$count > 0" | bc ) -eq 1 ]]; then
echo "The count percentage change ($count) is greater than zero"
elif [[ $(echo "$count < 0" | bc ) -eq 1 ]]; then
echo "The count percentage change ($count) is less than zero"
elif [[ "$count" == 0 ]]; then
echo "The count percentage change stays unchanged (is zero)"
else
echo "$count ... Something else is wrong here"
fi

Bash script to count the number of occurances of a string in a file

I have this function in my Bash script
if [ $numberOne -gt 10 ]
then
echo "$numberOne has occurred over 10 times"
echo "email me numberOne"
elif [ $numberTwo -gt 4 ]
then echo "$numberTwo has occurred over 4 times"
echo "email me numberTwo"
elif [ $numberThree -gt 4 ]
then echo "$numberThree has occurred over 4 times"
echo "email me numberThree"
elif [ $numberFour -gt 5 ]
then echo "$numberFour has occurred over 5 times"
echo "email me numberFour"
else echo "nothing found yet"
exit
fi
}
Info: I am port checking. I run a script every minute. When a port is found to be used I write it to a file and then read the file. The number of times it's found equates to minutes. 4 times is 4 minutes, I want to know if the port is active more that a number of minutes.
What I want to do:
3 numbers will populate a file. At some point one of them will be present more than 4 times and then the rest will also appear. At that point I want an alert when the first of them occurs or [all of them after the first occurrence]. Ideally the alert will be like this: "NumberOne has been open for 4 minutes". And after 1 minute it will be "5 minutes"-until I stop it or a threshold is reached, I don't know yet.
The problem:
The problem here is that when NumberOne occurs more than 10 times AND NumberTwo occurs 4 times after that it only echoes NumberTwo.
I thought I could use continue after each then, but I can't!
Also: my NumberOne variable. NumberOne=$(grep -wc "port=51555" monitor.txt)
To get the number of occurrences a string has on a file, use grep -c:
grep -c something file
An example application to this is:
file="/path/to/file"
numberOne_string="something"
numberOne=$(grep -c "$numberOne_string" "$file")
And about your logic the best option I think could only be:
if [[ numberOne -gt 10 || numberTwo -gt 4 || numberThree -gt 4 || numberFour -gt 5 ]]; then
if [[ numberOne -gt 10 ]]; then
echo "$numberOne has occurred over 10 times"
echo "email me numberOne"
fi
if [[ numberTwo -gt 4 ]]; then
echo "$numberTwo has occurred over 4 times"
echo "email me numberTwo"
fi
if [[ numberThree -gt 4 ]]; then
echo "$numberThree has occurred over 4 times"
echo "email me numberThree"
fi
if [[ numberFour -gt 5 ]]; then
echo "$numberFour has occurred over 5 times"
echo "email me numberFour"
fi
else
echo "nothing found yet"
fi
Or a negated version of it.
Another requires a variable:
nothing_found=true
if [[ numberOne -gt 10 ]]; then
echo "$numberOne has occurred over 10 times"
echo "email me numberOne"
nothing_found=false
fi
if [[ numberTwo -gt 4 ]]; then
echo "$numberTwo has occurred over 4 times"
echo "email me numberTwo"
nothing_found=false
fi
if [[ numberThree -gt 4 ]]; then
echo "$numberThree has occurred over 4 times"
echo "email me numberThree"
nothing_found=false
fi
if [[ numberFour -gt 5 ]]; then
echo "$numberFour has occurred over 5 times"
echo "email me numberFour"
nothing_found=false
fi
if [[ $nothing_found == true ]]; then
echo "nothing found yet"
fi
You are checking different variables... you don't need elif there... Change it with independent if's. For example:
if [ $numberOne -gt 10 ]
then
echo "$numberOne has occurred over 10 times"
echo "email me numberOne"
fi
if [ $numberTwo -gt 4 ]
then
echo "$numberTwo has occurred over 4 times"
echo "email me numberTwo"
if
if [ $numberThree -gt 4 ]
then
echo "$numberThree has occurred over 4 times"
echo "email me numberThree"
fi
if [ $numberThree -gt 5 ]
then
echo "$numberFour has occurred over 5 times"
echo "email me numberFour"
fi
if [ $numberOne -le 10 -a $numberTwo -le 4 -a $numberThree -le 4 -a $numberFour -le 5 ]
then
echo "nothing found yet"
exit
fi
Here is a refactoring which reduces code duplication.
found=false
while read variable count; do
value=${!$variable}
if [ "$value" -gt "$count" ]; then
echo "$value occurred more than $count times"
echo "email me $variable"
found=true
fi
done <<____HERE
numberOne 10
numberTwo 4
numberThree 4
numberFour 5
____HERE
if ! $found; then
echo "Nothing found yet"
fi
If you don't have Bash, you can use eval value="\$$variable" instead.
If you want to populate the variables on the fly, you could do the grep -c inside the loop, and put e.g. a regex, or just the port number, in the first column of the here document instead.

Resources