Here is my code
CURR_MNTH=$(date +'%m' -d 'now')
if [$CURR_MNTH < 04]
THIS_QTR=1
elif [$CURR_MNTH < 07] && [$CURR_MNTH > 03]
THIS_QTR=2
elif [$CURR_MNTH < 10] && [$CURR_MNTH > 07]
THIS_QTR=3
elif [$CURR_MNTH > 09]
THIS_QTR=4
fi
echo $THIS_QTR
I am trying to get the current quarter with the above logic, but the prompt says that i have `elif' unexpected error.. Can someone please help me
Provided that you use Bash, there are numerous errors:
no semicolons after the if statements;
no spaces between brackets and conditional expressions;
conjunctions should be given inside the same set of brackets;
consider using -lt and -gt for value tests.
The correct code would look like this:
CURR_MNTH=$(date +'%m' -d 'now')
if [[ $CURR_MNTH -lt 4 ]]; then
THIS_QTR=1
elif [[ $CURR_MNTH -lt 7 && $CURR_MNTH -gt 3 ]]; then
THIS_QTR=2
elif [[ $CURR_MNTH -lt 10 && $CURR_MNTH -gt 7 ]]; then
THIS_QTR=3
elif [[ $CURR_MNTH -gt 9 ]]; then
THIS_QTR=4
fi
echo $THIS_QTR
Consider running http://www.shellcheck.net/ on your code next time.
You can get the quarter from the month by a formula:
THIS_QTR=$(( 1 + (10#$CURR_MNTH - 1) / 3))
The 10# prefix indicates decimal number, thus preventing the leading 0 to be interpreted as octal number indicator.
Related
#!/bin/bash
clear
echo "Wishing according to Time of the PC"
h=$(date '+%H') #This line works, I've Checked.
if test $h -gt 6 -a $h -lt 12
then
echo "Good Morning"
elif test $h -gt 12 -a $h -lt 16
then
echo "Good Afternoon"
elif test $h -gt 16 -a $h -lt 20
then
echo "Good Evening"
else
echo "Good Night"
fi
Output should be coming according to My PC's time which is 4:00 PM but the above code isn't executing that if and elif conditions (I mean, if and elif are always returning false) and is directly jumping to else part. I am using Linux 7.9. I tried using nested if as well but it returns false always as well.
you're not capturing when $h is 16
only when it's less or more
see -ge (greater than or equal to) in the below
allow me to make this more idiomatic (use of test is not current practice, use [[ ... ]]):
h=$(date '+%H')
h=${h#0} # remove leading zero
if [[ $h -gt 6 && $h -lt 12 ]]
then
echo "Good Morning"
elif [[ $h -ge 12 && $h -lt 16 ]]
then
echo "Good Afternoon"
elif [[ $h -ge 16 && $h -lt 20 ]]
then
echo "Good Evening"
else
echo "Good Night"
fi
note that I remove any leading zero,
this is because a leading zero can make a number (e.g. 09)
interpreted as an octal, which is not what you want!
I have this simple comparison operator, it check if number is between 1 and 3 (1 and 3 included too). But if I assign number to 3,2 it still accepts as correct.
It should only accept those values 1-2-3
My code
if (("$number" >= 1 && "$number" <= 3)); then
echo 'Correct number'
fi
(("$number" >= 1 && "$number" <= 3)) is a Bash's stand-alone arithmetic expression.
Within an arithmetic expression, variables are expanded as-is and if they contain valid arithmetic expression's syntax elements, these are also interpreted.
number="3,2" expands as ((3,2)) in an arithmetic expression, where comma , is interpreted as a statements separator by Bash's arithmetic expressions.
Lets see:
$ number="3,2"; echo "$((number))"
2
$ number="3+2"; echo "$((number))"
5
$ number="3*2"; echo "$((number))"
6
The shell only understands integer arithmetic, but 3,2 is not a valid integer value.
It means that if you are unsure a variable contains a valid integer, it is unsafe for use within an arithmetic expression.
Always check that number contains a valid integer (see: Test whether string is a valid integer) before using in an arithmetic expression or within a test comparing integers.
# Check number is a valid integer before testing its range.
[[ $number =~ ^[-+]?[0-9]+$ ]] && (("$number" >= 1 && "$number" <= 3))
The other numeric test method [ "$number" -ge 1 ] && [ "$number" -le 3 ] as suggested in the other answers will error-out with: bash: [: 3,2: integer expression expected.
It also needs testing for valid integer:
[[ $number =~ ^[-+]?[0-9]+$ ]] && [ "$number" -ge 1 ] && [ "$number" -le 3 ]
With POSIX shell, there is no Regex test, so a different approach is needed:
case "${number#[+-]}" in(*[!0123456789]*|'')false;;esac &&
[ "$number" -ge 1 ] && [ "$number" -le 3 ]
An additional note about the pitfalls of using arithmetic expressions to compare numbers. Arithmetic expressions will handle leading 0 of an integer, as an octal:
$ (( 13 >= 12 )); echo $?
0
but
$ (( 013 >= 12 )); echo $?
1
Try this:
if [ "$number" -ge 1 ] && [ "$number" -le 3 ]; then
echo 'Correct number'
fi
You have to rewrite your code as follow:
if [ "$number" -ge 1 ] && [ "$number" -le 3 ]; then
echo 'Correct number'
fi
Look at https://tldp.org/LDP/abs/html/comparison-ops.html for further information.
#!/bin/bash
startdate=2009-02-21
enddate=2009-11-30
var=$startdate
while true
do
echo $var
touch $var.txt
#it's line 9
[[ "10#$var" -ge "$enddate" ]] || break
var=$(date +%Y-%m-%d --date "$var +1 day")
done
It returns the error
line 9:value too great for base (error token is "08")
Evidently, the error is in the expression 10#, but I can't think of a different way how to write the string, besides the ones I've already tried.
Convert your dates into seconds then do the comparison, this will be a better approach -
startdate=$(date -d 2009-02-21 +%s)
enddate=$(date -d 2009-11-30 +%s)
...
[[ "$startdate" -ge "$enddate" ]] || break
...
You are passing the whole date as a numeric expression, so 2009-02-01 is interpreted as 2009 - 2 - 1, i.e. 2009 - 3 = 2006. Try the following to see:
echo $(( 10#$var ))
But numbers starting with a 0 are interpreted as octal numbers, but 08 in so 2009-03-08 can't be interpreted as octal, as only digits 0-7 are permitted in octal numbers.
Maybe you need to compare the dates as string, not as numeric expressions?
[[ $var == $enddate || $var > $enddate ]] && break
Note I also changed || to &&. Also, >= doesn't exist, but you can replace the double comparison with
[[ ! $var < $enddate ]]
I want to do an if statement with three conditions that have to be satisfied at the same time. I am using Ubuntu Bash for Windows and the values $c1, $c2 and $c3 are non-integer (decimal negative numbers).
if [ (( $(echo "$c1 < 0" | bc -l) )) ] && [ (( $(echo "$c2 < 0" | bc -l) )) ] && [ (( $(echo "$c3 < 0" | bc -l) )) ];
then
>&2 echo -e " ++ Constraints OK"
else
>&2 echo -e " ++ Constraints WRONG"
fi
However, I get the following syntax error in the if line: syntax error near unexpected token `('
If I just put one condition:
if (( $(echo "$c1 < 0" | bc -l) ));
it works, but when I add the three of them as AND (&&), I get the error. Can anyone help me?
Considerably more efficient (assuming you know your values are numbers, and only need to check whether they're all negative) would be:
if [[ $c1 = -* ]] && [[ $c2 = -* ]] && [[ $c3 = -* ]]; then
>&2 echo " ++ Constraints OK"
else
>&2 echo " ++ Constraints WRONG"
fi
If you want to be more specific about the permissible formats (f/e, allowing leading spaces), a regex is another option, which similarly can be implemented more efficiently than spawning a series of subshells invoking bc:
nnum_re='^[[:space:]]*-([[:digit:]]*[.][[:digit:]]+|[[:digit:]]+)$'
if [[ $c1 =~ $nnum_re ]] && [[ $c2 =~ $nnum_re ]] && [[ $c3 =~ $nnum_re ]]; then
>&2 echo " ++ Constraints OK"
else
>&2 echo " ++ Constraints WRONG"
fi
First, pass the relational AND operators into bc to get rid of some punctuation (also only invokes bc once):
if (( $(echo "$c1 < 0 && $c2 < 0 && $c3 < 0" | bc -l) == 1 ))
then
>&2 echo -e " ++ Constraints OK"
else
>&2 echo -e " ++ Constraints WRONG"
fi
Although if it were me, I would create a shell function returning a "true" exit status if bc evaluates the result of an expression to non-zero. Then you can hide most of the ugly punctuation in one place separated from your main logic:
function bc_true() {
(( $(echo "$#" | bc -l) != 0 ))
}
And write a (IMO) cleaner shell expression:
if bc_true "$c1 < 0 && $c2 < 0 && $c3 < 0"
then
...
This question already has answers here:
Assigning default values to shell variables with a single command in bash
(11 answers)
Closed 5 years ago.
How would I write a Linux script to print numbers 1 through n, one on each line. But if n isn't specified, a default value of 10 will be used.
Example:
script name is value
./value 20 should print 1 through 20 on each line
./value should print 1 through 10 on each line by default
My Script:
#!/bin/bash
num=$1
for (( i = 1 ; i <= ${num} ; i++ ))
do
echo $i
done
Put in the rest of the substitution.
${num:-10}
Check the following:
#!/bin/bash
num=${1:-10}
for (( i = 1 ; i <= ${num} ; i++ ))
do
echo $i
done
You can simply catch an empty argument and replace it, with something like:
num=$1
[[ -z "$num" ]] && num=10
The advantage to this method is that you can apply arbitrary checks to the argument to ensure it's valid, not just catching an empty argument:
deflt=10
[[ -z "$num" ]] && echo 'No argument' && num=$deflt
[[ $num =~ -.* ]] && echo 'Starts with "-"' && num=$deflt
[[ ! $num =~ [0-9]+ ]] && echo 'Not integer' && num=$deflt
[[ $num -gt 99 ]] && echo 'Too big' && num=$deflt