Variable comparison error - linux

Hello everybody and sorry for bad English!
I'm trying to make a "telegram alert" and made this conditional:
NOW=$(date +%s)
NOWCHECK=$((NOW-3))
[...]
if ("$DATE" < "$NOWCHECK"); then # DATE is a string variable with seconds passed from 1/1/1970
...
fi
I get this error:
line 26: 1458939588: No such file or directory
What am I doing wrong?
Thanks in advance!

What you're experiencing is Bash is trying to execute the expression within (...). It's interpreted as running the $DATE command, and redirecting input to it from $NOWCHECK. But that's not what you want.
The operator for arithmetic operations is ((...)) not (...). Do like this:
if (("$DATE" < "$NOWCHECK")); then
And it would be better to drop the $ inside the ((...)):
if ((DATE < NOWCHECK)); then

Use:
if [[ "$DATE" -lt "$NOWCHECK" ]]; # -lt: less than

If you have this two variables set:
NOW=$(date +%s) NOWCHECK=$((NOW-3))
Then: Either switch to correct Arithmetic Expansion (( ... ))
if (( NOW < NOWCHECK )); then
...
fi
Or remove the < character (which is interpreted as a redirection and presents an error as the source file named as the value of NOWCHECK does not exist):
if [[ $NOW -lt $NOWCHECK ]]; then
...
fi
if [ "$NOW" -lt "$NOWCHECK" ]; then
...
fi

Related

bash: convert string to int & if int > #

I would like to have a bash script that checks if a file has more than # amount of lines but i have not yet got it working right and I'm not so sure on how to do it.
I've never used bash before.
right now i use: linesStr=$(cat log | wc -l) to get the amount of lines in the file (expect it to be a string). when echo'ing it gives me the number 30 which is correct.
but since its most likely a string it doesnt do the if-statement, so i need to have linesStr converted into a int called linesInt.
I also have the feeling the if-statement itself is not done correctly either.
#!/bin/bash
linesStr=$(cat log | wc -l)
echo $linesStr
if [$linesStr > 29]
then echo "log file is bigger than 29 lines"
#sed -i 1d log
fi
I would appreciate if anyone can give me a simple beginners solution.
No need for cat.
Lack of spaces around [ and ].
Use a numeric comparison operator instead of the redirect operator.
Here is a working script.
#!/bin/bash
linesStr=$( wc -l < log )
if [[ "$linesStr" -gt "29" ]]; then
echo Foo
fi
your if block of code is wrong if [$linesStr > 29] there should be a space after [ and before ]
#!/bin/bash
linesStr=$(wc -l < log )
echo $linesStr
if [[ $lineStr -gt 29 ]];then
echo "log file is bigger than 29 lines"
fi
it is advisable that you always use [[ ]] with an if statement rather than using [ ]. Whenever you want to compare integers dont use > or <, use -gt -ge -lt -le. And if you want to do any form of mathematical comparison it is advisable that you use (( )).
(( lineStr > 29 )) && {
# do stuff
}
you should also note that you don't need the bash comparison operators or getting the value of a variable with $ when using (( ))
There are no string or integer types to convert. The problem is that you're using the wrong comparison operator. For numeric comparison use if [ $linesStr -gt 29 ]. Read man bash section CONDITIONAL EXPRESSIONS for available operators.
(( $(wc -l < log) > 29 )) && echo too long

How do I see if a parameter stars with an uppercase letter in Bash?

I need to make a script that iterates through a list of parameters and checks/counts if the parameter starts with an uppercase letter. I have some starter code but I am stuck and would appreciate any help!
Several notes:
You're missing the =~ operator for a regular expression
Your if is not ended by a fi.
Using [A-Z] doesn't work in all locales, and is needlessly fragile. Some collation orders are of the form AaBbCcDd, and thus A-Z contains a, b, etc; [[:upper:]] is guaranteed to do the right thing everywhere.
Unquoted $# behaves exactly the same as unquoted $*. If you want to correctly honor the quoting and escaping used when your function was first called, use "$#", quoted.
Consider instead:
#!/bin/bash
(( "$#" )) || { echo "Error: No arguments given" >&2; exit 1; }
re='^[[:upper:]]' # store regex in a variable for compatibility with old bash releases
for word in "$#"; do
[[ $word =~ $re ]] && ((++count))
done
echo "$count arguments started with upper-case characters"
Alternately, by using a case statement you can avoid requiring bash, and also check for other types:
for word in "$#"; do
case $word in
[[:upper:]]*) (( ++upper_count )) ;;
[[:lower:]]*) (( ++lower_count )) ;;
[[:digit:]]*) (( ++digit_count )) ;;
esac
done
echo "Found $upper_count arguments starting with upper-case letters"
echo "Found $lower_count arguments starting with lower-case letters"
echo "Found $digit_count arguments starting with digits"
#! /bin/bash
if [ $# -eq 0 ]; then
echo Error
exit 1
fi
COUNT=`echo "$#" | tr ' ' '\n' | grep "^[A-Z]" | wc -l`
echo $COUNT

use of special characters in if statement in bash

I'm unfamiliar with bash scripting. I wrote a script check arguments. the code is:
for (( i=1; i<=4; i++ ))
do
if ! [[ "$"$i =~ .*[^0-9].* ]]; then
echo "bad input was $i"
fi
done
Actually i want to split non numerical arguments, But it seems that "$"$i is wrong because the answer is always true or false independent of arguments.
can anybody tell me what is the mistake?
You seem to be trying to use indirect parameter expansion.
for (( i=1; i<=4; i++ ))
do
if ! [[ ${!i} =~ .*[^0-9].* ]]; then
echo "bad input was $i"
fi
done
However, it's cleaner to just iterate over the parameters directly, rather than over their position:
for arg in "${#:1:4}"; do
if ! [[ $arg =~ .*[^0-9].* ]]; then
echo "bad input was $arg"
fi
done
If condition should be like this:
if [[ ! "$i" =~ [^0-9] ]]; then
OR remove 2 negatives:
if [[ "$i" =~ [0-9] ]]; then
OR use glob:
if [[ "$i" == *[0-9]* ]]; then
Which means $i contains a digit 0-9
Update: Based on your comments it looks like you are looking for BASH variable indirection like this script check-num.sh:
#!/bin/bash
for (( i=1; i<=$#; i++ )); do
[[ "${!i}" != *[0-9]* ]] && echo "bad input was ${!i}"
done
You can run this script as: ./check-num.sh 1 2 x 4 a
Note how ${!i} syntax is being used here to access the variable's $1, $2, $3 etc that is called BASH variable indirection. You shouldn't use $$i for this purpose.
As per BASH manual:
If the first character of parameter is an exclamation point, a level of variable indirection is introduced. Bash uses the value of the variable formed from
the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the
value of parameter itself.
Use something like this :
for i in "$#"; do
[[ $i =~ .*[^0-9].* ]] || echo "bad input was $i"
done
N.B : It's not necessary to use doubles quotes arround the variable with the [[ internal instruction.

Is value in range with bash shell

In bash shell, how can be value checked if within range by most effective way?
Example:
now=`date +%H%M`
if [ $now -ge 2245 ] && [ $now -le 2345 ] ; then
...
fi
...this one is working, but with using now variable.
Other option is:
if [ $((`date +%H%M`)) -ge 2245 ] && [ $((`date +%H%M`)) -le 2345 ] ; then
...
fi
...without variable, but with execution of date twice.
How to do it with one date execution and no variable at all?
First off, as a general rule, I'm pretty sure you need EITHER to use a variable OR run the command twice to do multiple comparisons on arbitrary numbers. There is no such notation as if [ 1000 -lt $(date '+%H%M') -lt 2000 ];.
Also, you don't need to put your backquoted commands inside $((...)). The result of the backquoted command is a string which /bin/[ will be interpreted by -gt or -le as a number.
if [ `date '+%H%M'` -gt 2245 -a `date '+%H%M'` -lt 2345 ]; then
That said, as an option for the times in your example, you can try using a smarter date command line.
In FreeBSD:
if [ `date -v-45M '+%H'` -eq 22 ]; then
Or in Linux:
if [ `date -d '45 minutes ago' '+%H'` -eq 22 ]; then
You can use Shell Arithmetic to make your code clear.
now=`date +%H%M`
if ((2245<now && now<2345)); then
....
fi
I would write:
if ( now=$(date +%H%M) ; ! [[ $now < 2245 ]] && ! [[ $now > 2345 ]] ) ; then
...
fi
which is mostly equivalent to your first example, but restricts the $now variable to a subshell (...), so at least it doesn't pollute your variable-space or risk overwriting an existing variable.
It also (thanks to shellter's comment) avoids the problem of $now being interpreted as an octal number when %H%M is (for example) 0900. (It avoids this problem by using string comparison instead of integer comparison. Another way to avoid this problem would be to prefix all values with a literal 1, adding 10,000 to each of them.)
#!/bin/bash
while :
do
MAX_TIME="1845"
MIN_TIME="1545"
if ( now=$(date +%H%M) ; ! [[ $now < $MIN_TIME ]] && ! [[ $now > $MAX_TIME ]] ) ;
then
echo "You are in time range and executing the commands ...!"
else
echo "Maximum Time is $MAX_TIME ...!"
# echo "Current Time is $now .....!"
echo "Minimum Time is $MIN_TIME ....!"
fi
sleep 4
done
#nohup sh /root/Date_Comp.sh > /dev/null 2>&1 &

Multiple -a with greater than / less than break bash script

I wrote a bash script that performs a curl call only during business hours. For some reason, the hourly comparison fails when I add an "-a" operator (and for some reason my bash does not recognize "&&").
Though the script is much larger, here is the relevant piece:
HOUR=`date +%k`
if [ $HOUR > 7 -a $HOUR < 17 ];
then
//do sync
fi
The script gives me the error:
./tracksync: (last line): Cannot open (line number): No such file
However, this comparison does not fail:
if [ $DAY != "SUNDAY" -a $HOUR > 7 ];
then
//do sync
fi
Is my syntax wrong or is this a problem with my bash?
You cannot use < and > in bash scripts as such. Use -lt and -gt for that:
if [ $HOUR -gt 7 -a $HOUR -lt 17 ]
< and > are used by the shell to perform redirection of stdin or stdout.
The comparison that you say is working is actually creating a file named 7 in the current directory.
As for &&, that also has a special meaning for the shell and is used for creating an "AND list" of commands.
The best documentation for all these: man bash (and man test for details on comparison operators)
There are a few answers here but none of them recommend actual numerical context.
Here is how to do it in bash:
if (( hour > 7 && hour < 17 )); then
...
fi
Note that "$" is not needed to expand variables in numerical context.
I suggest you use quotes around variable references and "standard" operators:
if [ "$HOUR" -gt 7 -a "$HOUR" -lt 17 ]; ...; fi
Try using [[ instead, because it is safer and has more features. Also use -gt and -lt for numeric comparison.
if [[ $HOUR -gt 7 && $HOUR -lt 17 ]]
then
# do something
fi

Resources