[wellylug] bash / sed / awk tricky question

jfouhy at paradise.net.nz jfouhy at paradise.net.nz
Fri Feb 4 16:08:19 NZDT 2005


Quoting Glen Ogilvie <nelg at linuxsolutions.co.nz>:

> Any suggestions of how do to this in a script would be appricated, as it
> will help me learn some more complicated awk/sed scripting.

Here is my crack at an awk solution:

------ proc.awk -----
# This block will execute at the beginning of the script.
BEGIN{
        # Set the field separator.
        FS = "-";
}

# Comparison function for doing things like "2.4.25" > "2.4.3"
function cmp(s1, s2){
        # Split s1 into array a1 with separator .
        # n is the length of the array (indices 1 .. n).
        n = split(s1, a1, /\./);
        # Assume s2 has the same length.
        split(s2, a2, /\./);

        for(i=1; i <= n; i++){
                if(a1[i] < a2[i]){
                        return -1;
                } else if(a1[i] > a2[i]){
                        return 1;
                }
        }
        return 0;
}

# This block will execute once for every line.
# $0 is the whole line; $1 through $NF are the fields (split by FS).
{
        if($1 in rpms){
                if($2 == "devel"){
                        if(cmp($3, versions[$1]) >= 0){
                                rpms[$1] = $0;
                                versions[$1] = $3;
                        }
                } else {
                        if(cmp($2, versions[$1]) > 0){
                                rpms[$1] = $0;
                                versions[$1] = $2;
                        }
                }
        } else {
                rpms[$1] = $0;
                versions[$1] = $2;
        }
}

# This block executes at the end.
END{
        for(n in rpms){
                print rpms[n];
        }
}
-----------------------

$ awk -f proc.awk test | sort
liblibinstpatch0-devel-1.0.0beta_20041028-1.mdk10.1.thac.i586.rpm
liblilypond-2.5.2-1thac.i586.rpm
liblo0-0.13-1.mdk10.1.thac.i586.rpm
tkchooser2-0.65.2-3.mdk10.1.thac.i586.rpm
us428control-1.0.8-0.rc2.3.mdk10.1.thac.i586.rpm

-----------------------

Some comments ...

1. Arrays in awk are maps, where keys can be strings numbers.
2. Variables in awk don't need to be initialised. 
3. The comparison function probably needs to be a bit smarter, to cope with
things like 1.0.0beta_20041028.
4. The code to find the version is a bit naive. You could go hunting for the
version by doing something like this:

------------------------
versionexp = /[:digit:]+(\.[:digit:]+)*/;  # Put this in the BEGIN block.

for(i = 2; i <= NF; i++){
        if($i ~ versionexp){
                version = $i;
        }
}
------------------------

HTH.

-- 
John.




More information about the wellylug mailing list