shell script compare numbers return illegal number - shell

I have a script that simply needs to check a timestamp with another timestamp in an if-statement.
However, it constantly returns an Illegal number
currentTime=$(($(date +%s) -d ))
cutoffTime=$((currentTime - 604800))
cutoffTime is the first variable to compare
time="$(echo $notes | grep -oP '^[0-9]{0,10}')"
time is the second variable to compare and is parsed from a string.
The if-statement looks like this
if [ $(($time)) -lt "$cuttofTime" ];
but even if I try
if [ "$time" -lt "$cuttofTime" ];
or
if [ "$time" < "$cuttofTime" ];
It will still say 'Illegal number'. I have no clue why it says illegal number when converting $time to a number in the first if-statement.
What is the proper way to do this in shell scripts and why does it state it is an illegal number?

Related

Bash parameter expansion from both sides

I'm getting dollar values from a file into the variable in the form
p=$1234.56, and would like remove $ and decimal places to get integer value in my conditional like
if [[ ${p%%.*} < 1000]]; then p=${p}0; fi
But this doesn't remove the $ sign, and I don't want to do it in 2 steps and modify actual variable, as I need $ for later use.
How to get integer value regardless of number of digits ie ($2.2, $123456.1234...)?
Unfortunately, there is no way to avoid performing multiple parameter expansions if you need to remove multiple patterns, in the general case.
In simple cases like this, you can avoid a temporary variable just by assigning back to the same variable.
p=${p#\$}
p=${p%.??}
In your specific scenario, of course, you can just replace any nonnumeric characters globally, and accept that the number will be multiplied by 100. You will obviously then need to multiply the number you compare against correspondingly.
if [[ ${p//[!0-9]/} < 100000 ]]
Of course, for this to work, you need to be sure that your variable's value conforms to your expectations. If the value could have different numbers of decimal places depending on what a user passes in or where you read the input from, you need to perform additional normalizations, or just use a different approach entirely (frequently you'd pass your input to Awk or bc which support floating point math, unlike the shell).
However, the string substitution parameter expansion ${variable//pattern/replacement} is a Bash extension, and not portable to Bourne/POSIX sh.
It's not possible without modifying the var. But you can use a subshell process with something like sed
if [[ $(sed 's/\$\([0-9]*\)\..*/\1/' <<< $p) < 1000 ]]; then p=${p}0; fi
Another option will be to use cut command to extract the substring
before the dot (if any). Then you can say something like:
p='$1234.56'
[[ $(cut -d. -f1 <<< "${p#\$}") < 1000 ]] && p=${p}0
echo "$p"
BTW the expression [[ str1 < str2 ]] performs lexicographical comparison,
meaning [[ 20 < 1000 ]] returns false because 20 sorts after
1000 in dictionary order.
If what you want to do is arithmetic comparison, you'll need to say
[[ val1 -le val2 ]] or (( val1 < val2 )) such as:
p='$1234.56'
[[ $(cut -d. -f1 <<< "${p#\$}") -le 1000 ]] && p=${p}0
echo "$p"

ash: -c: unknown operand

I'm trying to run a ash script that constantly checks how many characters are in a file and execute some code if it reaches at least 170 characters or if 5 seconds have passed. To do that I wanted to call wc -c, however it keeps telling me it has an unknown operand.
The code:
#!/bin/ash
while true; do
secs=5
endTime=$(( $(date +%s) + secs ))
while [ /usr/bin/wc -c < "/tmp/regfile_2" -gt 170 ] || [ $(date +%s) -lt $endTime ]; do
#more code
It's output is ash: -c: unknown operand
You want to check whether the output from wc meets a specific condition. To do that, you need to actually execute wc, just like you already do with date to examine its output.
while [ $(wc -c < "/tmp/regfile_2") -gt 170 ] ||
[ $(date +%s) -lt $endTime ]; do
# ...stuff
Notice the $(command substitution) around the wc command.
As you can see from the answer to the proposed duplicate Checking the success of a command in a bash `if [ .. ]` statement your current command basically checks whether the static string /usr/bin/wc is non-empty; the -c after this string is indeed unexpected, and invalid syntax.
(It is unclear why you hardcode the path to wc; probably just make sure your PATH is correct before running this script. There are situations where you do want to hardcode paths, but I'm guessing this isn't one of them; if it is, you should probably hardcode the path to date, too.)

How to convert shell script variable from string to an integer

My script has a line that measures the number of instances of a process being run
procs=$(pgrep -f luminati | wc -l);
However, even though the content of $procs is a numeral, the shell script is not storing $procs as an integer. It is being stored as a string.
Therefore I cannot run conditionals like
if $procs > 3
Is there any way to convert this variable to integer type?
In bash > is truncate which writes to a file. You probably have a file called 3 now. You should use the comparitor -gt:
if [[ "$procs" -gt 3 ]]; then
...
fi
Also, you don't have separate types for integers and strings.
Edit:
As #chepner explained, for POSIX compatibility you should use single brackets:
if [ "$procs" -gt 3 ];
Should be
if [[ "$procs" -gt 3 ]]
then
...
fi

Comparing two date strings in bash

I am having trouble with a script that checks the date of a table to make sure the slave's data is up to date
The problem is that the date equality is coming back incorrect:
NOW=$(date +"%Y-%m-%d")
VALUE=`mysql -uroot -p database -e "select DATE_FORMAT(create_date,'%Y-%m-%d') as '' from actions order by id desc limit 1"`
echo $NOW $VALUE
if [ "$?" -ne 0 ]; then
MSG="MySQL check data date failed"
echo $MSG
echo $MSG > $MESSAGE
/bin/mail -s "$SUBJECT" "$EMAIL" < $MESSAGE
exit 7
fi
if [ "$NOW" != "$VALUE" ]; then
echo "not equal"
fi
The output is that they are not equal:
2011-12-08 2011-12-08
not equal
My guess is that I am comparing two different types, but according the bash documentation that shouldn't be the case.
Can someone explain this to me?
Thanks
If you turn on the shell debugging set -vx, you'll see each line (or block of code like while, for loops) displayed, (verbose mode), then you get the line as it being executed with all variables expanded to their current values. Change the last conditional to
if [ "X${NOW}X" != "X${VALUE}X" ] ; then ....
And you can easily tell if $NOW or $VALUE have any extra while-space characters embedded. Once you can see where the differences are, then you can easily determine how to fix the assignment of those values.
I hope this helps.

test command in KornShell (ksh)

I have a question on the test command in the KornShell (ksh). I know -ne is for comparing integers and != is for comparing strings. How will the test command behave if one argument is a string and the other is an integer? I have below conditions in my code and both are working properly.
Code:
myCount=1
myCount=`expr $myCount+ 0`
temp=`ps -aef | grep damn | wc -l`
if [ $temp -ne $myCount]; then
echo ERROR Number
fi
if [ $temp != $myCount ]; then
echo ERROR Strings
fi
Output:
ERROR Number
ERROR Strings
The type is not relevant because it's a simple text substitution. In other words, the value of the variable $temp will be substituted in place of $temp (for example).
At least for the version of ksh I'm running, for the numeric comparison, if the value starts with a non-numeric, it will equate to 0. If it starts with a numeric but contains non-numerics, you will get an error.
For example:
$ export s1=xyz
$ export s2=7xyz
$ export i1=0
$ if [ $i1 -eq $s1 ]
> then
> echo equal
> fi
equal
$ if [ $i1 -eq $s2 ]
> then
> echo equal
> fi
ksh: 7xyz: bad number `7xyz'
However, based on your comments, that may not be the case for all versions of ksh.
Based on that, I would try to ensure that you use string comparisons for strings and numeric comparisons for numbers. Anything else may be non-portable.
But your code is flawed anyway.
temp=ps -aef | grep damn | wc -l
will always return at least 1, since it will find the grep command as well as being a string padded with leading spaces, which is why both of your tests are true.
Piping to wc is also unnecessary since the -c switch of grep will count for you.
better code would be:
temp=ps -aef |grep damn |grep -cv grep
which will return the number of running instances of processes containing the damn string and it will be a number.
Using ksh93 and GNU coreutils expr 7.4 your command:
myCount=`expr $myCount+ 0`
gives me a syntax error and sets myCount to null which causes both if statements to output "ksh: [: argument expected" errors. Try putting a space before the plus sign. Also, there needs to be a space before ].
You shouldn't need to convert myCount or temp to integers. The coercion of myCount using expr is completely unnecessary.
I prefer this form for comparing integers since it allows you to use symbolic comparison operators such as != and > instead of -ne and -gt:
if (( $temp != $myCount ))

Resources