Version Comparison using KSH - unix

I'm trying to write a function to compare the versions of the products.
my versions can be XX.XX.XX or xx-xx-xx either it's separated with "." or "-"
and number of fields can be different either xx.xx or xx.xx.xx or xx.xx.xx.xx
the versions which im gonna compare will identical in delimiters and with the fields
#!/bin/ksh
set -x
compareVersions ()
{
typeset IFS='.'
typeset -a v1=( $1 )
typeset -a v2=( $2 )
typeset n diff
for (( n=0; n<4; n+=1 )); do
diff=$((v1[n]-v2[n]))
if [ $diff -ne 0 ] ; then
[ $diff -le 0 ] && echo '-1' || echo '1'
return
fi
done
echo '0'
} # ---------- end of function compareVersions ----------
#compareVersions "6100-09-03" "6100-09-02"
compareVersions "6100.09.03" "6100.09.02"
Please check and give me suggestions
I have tried with the below thing which i have got a other post.. but there is no luck.. hope there should some modification should be done. I have to use across platforms ( linux, solaris, AIX ) so i have preferred KSH, i have idea only in shell scripting though.

Create arrays from version strings, then loop through them comparing elements one by one and return values accordingly. The following example will compare two version strings and returns either 0 (versions are equal), 1 (the first version string is greater) or 2 (the second version string is greater).
#!/bin/ksh
function vertest {
set -A av1 `echo $1 | sed -e 's/\'$3'/ /g'`
set -A av2 `echo $2 | sed -e 's/\'$3'/ /g'`
for (( i=0; i < ${#av1[#]}; i++ )) ; do
[[ ${av1[$i]} -eq ${av2[$i]} ]] && continue
[[ ${av1[$i]} -gt ${av2[$i]} ]] && return 1
[[ ${av1[$i]} -lt ${av2[$i]} ]] && return 2
done
return 0
}
v1="2-7-2-1"
v2="1-8-0-1"
vertest $v1 $v2 '-'
exit $?
# end of file.
This example will exit to shell with exit code 1. Should you change $v1 to 1-7-2-1, it will exit to shell with exit code 2. And so on, and so forth.
The separator escaping is not complete, but this works with most reasonable separators like a period (.) and a dash (-). This, as well as parameter checking for the vertest() is left as an exercise for the reader.

When the format of both numbers is equal (leading zero as your example), you can use
compareVersions ()
{
val1=$(echo $1| tr -d ".-")
echo ${val1}
val2=$(echo $2| tr -d ".-")
echo ${val2}
if [ ${val1} -gt ${val2} ] ; then
echo 1
return
fi
if [ ${val1} -eq ${val2} ] ; then
echo 0
return
fi
echo '-1'
} # ---------- end of function compareVersions ----------

Related

How to complete a variable number of arguments containing spaces

I've build a command line tool and I need to complete arguments with zsh. I never wrote a zsh completion function so I looked in the scripts provided with zsh but I missed something so that it could work properly.
So, mytool can take a variable number of values and two options.
Here are some call examples:
mytool ONE
mytool ONE TWO
mytool AAA BBB CCC DDD EEE --info
In order to complete the values, I hava another executable that outputs all possible lines to stdout, like this simplified script named getdata:
#!/usr/local/bin/zsh
echo ONE
echo TWO ONE
echo TWO TWO
# ... a lot of lines
echo OTHER ONE
echo ONE ANOTHER LINE
echo AAA BBB CCC DDD EEE
Each completion must match to a whole line, so in my getdata example, it will not be possible to just complete with the value TWO because this whole line does not exist, it must be TWO ONE or TWO TWO.
As this script is quite time consuming, I would like to use zsh caching feature. So, here is my zsh complete script:
compdef _complete_mytool mytool
__mytool_caching_policy() {
oldp=( "$1"(Nmh+1) ) # 1 hour
(( $#oldp ))
}
__mytool_deployments() {
local cache_policy
zstyle -s ":completion:${curcontext}:" cache-policy cache_policy
if [[ -z "$cache_policy" ]]; then
zstyle ":completion:${curcontext}:" cache-policy __mytool_caching_policy
fi
if ( [[ ${+_mytool_values} -eq 0 ]] || _cache_invalid mytool_deployments ) \
&& ! _retrieve_cache mytool_deployments;
then
local -a lines
_mytool_values=(${(f)"$(_call_program values getdata)"})
_store_cache mytool_deployments _mytool_values
fi
_describe "mytool values" _mytool_values
}
_complete_mytool() {
integer ret=1
local -a context expl line state state_descr args
typeset -A opt_args
args+=(
'*:values:->values'
'--help[show this help message and exit]'
'(-i --info)'{-i,--info}'[display info about values and exit]'
'(-v --version)'{-v,--version}'[display version about values and exit]'
)
_call_function res __mytool_deployments
return ret
}
But when I try to complete, spaces are escaped with backslash, and I don't want this behaviour.
mytool OTHER\ ONE
The options seem not to be completed too... So, any help will be greatly appreciated.
Thanks to okdana on the freenode zsh channel who helped me a lot.
So, the solution is:
compdef _complete_mytool mytool
__mytool_caching_policy() {
oldp=( "$1"(Nmh+1) ) # 1 hour
(( $#oldp ))
}
__mytool_deployments() {
local cache_policy
zstyle -s ":completion:${curcontext}:" cache-policy cache_policy
if [[ -z "$cache_policy" ]]; then
zstyle ":completion:${curcontext}:" cache-policy __mytool_caching_policy
fi
if ( [[ ${+_mytool_values} -eq 0 ]] || _cache_invalid mytool_deployments ) \
&& ! _retrieve_cache mytool_deployments;
then
local -a lines
_mytool_values=(${(f)"$(_call_program values getdata)"})
_store_cache mytool_deployments _mytool_values
fi
_describe "mytool values" _mytool_values -Q
}
_complete_mytool() {
_arguments : \
': :__mytool_deployments' \
'--help[show this help message and exit]' \
'(-i --info)'{-i,--info}'[display info about values and exit]' \
'(-v --version)'{-v,--version}'[display version about values and exit]'
}

Break the nested while loops in unix scripting

Have two files:
file1 is having the key words - INFO ERROR
file2 is having the list of log files path - path1 path2
I need to exit out of the script if any of the condition in any of the loops failed.
Here is the Code:
#!/bin/bash
RC=0
while read line
do
echo "grepping from the file $line
if [ -f $line ]; then
while read key
do
echo "searching $key from the file $line
if [ condition ]; then
RC=0;
else
RC=1;
break;
fi
done < /apps/file1
else
RC=1;
break;
fi
done < apps/file2
exit $RC
Thank you!
The ansewer to your question is using break 2:
while true; do
sleep 1
echo "outer loop"
while true; do
echo "inner loop"
break 2
done
done
I never use this, it is terrible when you want to understand or modify the code.
Already better is using a boolean
found_master=
while [ -n "${found_master}" ]; do
sleep 1
echo "outer loop"
while true; do
echo "inner loop"
found_master=true
break
done
done
When you do not need the variable found_master it is an ugly additional variable.
You can use a function
inner_loop() {
local i=0;
while ((i++ < 5)); do
((random=$RANDOM%5))
echo "Inner $i: ${random}"
if [ ${random} -eq 0 ]; then
echo "Returning 0"
return 0
fi
done;
return 1;
}
j=0
while ((j++ < 5 )); do
echo "Out loop $j"
inner_loop
if [ $? -eq 0 ]; then
echo "inner look broken"
break
fi
done
But your original problem can be handles without two while loops.
You can use grep -E "INFO|ERROR" file2 or combining the keywords. When the keywords are on different lines in file1, you can use grep -f file1 file2.
Replace condition with $(grep -c ${key} ${line}) -gt 0 like this:
echo "searching $key from the file $line
if [ $(grep -c ${key} ${line}) -eq 0 ]; then
It will count the each key-word in your log-file. If count=0 (pattern didn't found), running then. If found at least 1 key, running else, RC=1 and exit from loop.
And be sure, that your key-words can't be substrings of the longest words, or you will get an error.
Example:
[sahaquiel#sahaquiel-PC Stackoverflow]$ cat file
correctstringERROR and more useless text
ERROR thats really error string
[sahaquiel#sahaquiel-PC Stackoverflow]$ grep -c ERROR file
2
If you wish to avoid count 2 (because counting first string, obliviously, bad way), you should also add two keys for grep:
[sahaquiel#sahaquiel-PC Stackoverflow]$ grep -cow ERROR file
1
Now you have counted only the words equal to your key, not substrings in any useful strings.

How to group conditional expressions when using [[ ]] in zsh

I'm trying to group conditional expressions in zsh.
if [[ ( ! chkchroot ) || ( $# -lt 1 ) ]]; then
echo "usage: $0 [command]"
echo " run this inside a chroot"
return 1
fi
However this fails with a parsing error. Here, chkchroot is a shell function.
In pure POSIX, one can do this.
if [ \( ! chkchroot \) -o \( $# -lt 1 \) ]; then
echo "usage: $0 [command]"
echo " run this inside a chroot"
return 1
fi
Is there a way one can do this with the [[ ]] syntax in zsh?
It sounds like you have a tool chkchroot that you want to run. Your posted code is not how you run commands in an if statement.
To run chkchroot as a command, do not include it inside [[ .. ]]:
if ! chkchroot || [[ $# -lt 1 ]]
then
echo "foo"
fi
Bash interprets your chkchroot as an implicit -n chkchroot (which is always true and does not run chkchroot). Zsh does not allow this, which is why it complains. It's not related to the parentheses.

zsh: parse error: condition expected: "$1"

I tried to write a script to compile java files with gentoos java-config but i ended up getting an error
zsh: parse error: condition expected: "$1" Can anyone tell me what this means and why it gets reported at line 16 in the function.
function jComp() {
local java_mods = ""
if (( $# == 0)); then
echo "using javac on .java in folder"
`javac *.java`
return 0
elif [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then
echo "Usage: jComp [java modules] [file]"
echo
echo "Options:"
echo " -h, This help message."
echo "modules has to be in the (java-config -l) list"
echo
echo "Report bugs to <tellone.diloom#gmail.com>."
return 0
fi
if [[ "$(java-config -v)" == "" ]]; then
echo "This script depends on java-config"
return 1
elif [[ "$1" =="-d" ]] || [[ "$1" == "--default"]]; then
`javac -cp .:$(java-config -p junit-4) *.java`
if [[ $# == 2 ]]; then
`javac -c .:$(java-config -p junit-4) "$2"`
return 0
fi
fi
while (( $# > 1 )); do
if [[ ! -f "$1" ]]; then
java_mods="$java_mods $1"
shift
continue
fi
done
`javac -cp .:$(java-config $java_mods)`
return 0
}
Links and comment are welcome. Thanks in advance
It looks like your code is trying to compare a string stored in argument $1 to the string -d but the comparison is missing a space after the double equal sign:
elif [[ "$1" =="-d" ]] || [[ "$1" == "--default"]]; then
^
elif [[ "$1" == "-d" ]] || [[ "$1" == "--default"]]; then
I haven't tried the code but, do try and let me know if it solved it !
Btw, it also looks like the second comparison will also fail because of a lack of space before the double square closing brackets:
elif [[ "$1" == "-d" ]] || [[ "$1" == "--default"]]; then
^
elif [[ "$1" == "-d" ]] || [[ "$1" == "--default" ]]; then
All your backticked commands look wrong. You want to run the commands, not interpret their output as a command to run, right? If so, remove all the backticks from the javac invocations.
Then there is a missing space in [[ "$1" =="-d" ]] to make the == a separate token (and another as pointed out by leroyse).

if [ $? -ne 0 ] then syntax error then unexpected

I have been trying to execute the following UNIX shell script which is not working.
I am running it by KornShell (ksh).
echo $?;
if [ $? -ne 0 ]
then
failed $LINENO-2 $5 $6
fi
failed()
{
echo "$0 failed at line number $1";
echo "moving $2 to failed folder"
}
This is giving an error saying Syntax error:then unexpected.. Basically I have to check for the last executed ksh script's highest/last statement's return code and if it is not equal to zero I have to call function failed with the given parameters. I tried putting semicolon before then but that also did not work.
Can you please help?
Edit1: Based on the inputs I changed code. Still the same problem exists.
ksh ../prescript/Pre_process $1 $2 $3
rc=$?;
if [[ $rc -ne 0 ]];then
echo "failed";
exit 1;
Edit2:
It is working for the then part by using double squared brackets. I feel I used code of bash script for ksh. I am facing problem in function call of failed. Please let me know appropriate way of function call in ksh for this example
This looks like bash rather than ksh
failed() {
echo "$0 failed at line number $1";
echo "moving $2 to failed folder"
}
if [[ $? -ne 0 ]]
then
failed $LINENO-2 $5 $6
fi
You need to be careful. The first operation on $? will usually clear it so that your if won't work anyway.
You would be better off using:
rc=$?
echo $rc
if [ $rc -ne 0 ]
:
Other than that, it works fine for me:
$ grep 1 /dev/null
$ if [ $? -ne 0 ]
> then
> echo xx
> fi
xx
$ grep 1 /dev/null
$ echo $?;
1
$ if [ $? -ne 0 ]
> then
> echo yy
> fi
$ _
Note the lack of output in the last one. That's because the echo has sucked up the return value and overwritten it (since the echo was successful).
As an aside, you should let us know which UNIX and which ksh you're actually using. My working version is ksh93 under Ubuntu. Your mileage may vary if you're using a lesser version.
It looks like, from your update, your only problem now is the function call. That's most likely because you're defining it after using it. The script:
grep 1 /dev/null
rc=$?
if [ $rc -ne 0 ]
then
failed $rc
fi
failed()
{
echo Return code was $1
}
produces:
qq.ksh[6]: failed: not found
while:
failed()
{
echo Return code was $1
}
grep 1 /dev/null
rc=$?
if [ $rc -ne 0 ]
then
failed $rc
fi
produces
Return code was 1
you are missing semicolons at the end of the lines:
if [ $? -ne 0]; then
# …

Resources