Hubba's Blog

Notes from a Linux/Unix Engineer

Archive for the Shell Scripting category

Version comparison using rpm

Posted on Thu, Feb 20, 2025 at 11:35 by Hubertus A. Haniel

I have been playing a little bit with ChatGPT and its code generators and while doing this I stumbled across this. I wrote about versiion comparison in a previos post which is sort of a common thing that keeps coming up and I have used the function that I refer to there lots of times. It seems that rpm actually has a build in function to do this which returns result codes so you can refer to this with a function like this but obviously it will not work on other platforms and it seems that this has not been available on all rpm versions but I do not know when it was introduced:

compare_rpm_versions() {
    local version1="$1"
    local version2="$2"
    
    if [[ -z "$version1" || -z "$version2" ]]; then
        printf "Error: Two versions must be provided\n" >&2
        return 1
    fi

    if ! command -v rpm &>/dev/null; then
        printf "Error: rpm command not found\n" >&2
        return 2
    fi

    if rpm --eval "%{lua: print(rpm.vercmp('$version1', '$version2'))}" &>/dev/null; then
        local result; result=$(rpm --eval "%{lua: print(rpm.vercmp('$version1', '$version2'))}")
        case "$result" in
            1)  printf "%s is newer than %s\n" "$version1" "$version2"; return 0 ;;
            0)  printf "%s and %s are identical\n" "$version1" "$version2"; return 0 ;;
            -1) printf "%s is older than %s\n" "$version1" "$version2"; return 0 ;;
            *)  printf "Error: Unexpected comparison result: %s\n" "$result" >&2; return 3 ;;
        esac
    else
        printf "Error: Failed to compare versions\n" >&2
        return 4
    fi
}    
  
Edited on: Wed, Jun 04, 2025 15:00

Posted in HowTo (RSS), Packaging (RPM) (RSS), Shell Scripting (RSS), System - Linux (RSS)

Colour output in your scripts

Posted on Wed, Aug 02, 2023 at 13:03 by Hubertus A. Haniel

On Linux I have been using tput to produce colours in my output but then I noticed the other day that this does not actually seem to work on Solaris but I am not sure why so I had to resort to the old fashioned way of using escape sequences. This works perfectly fine in Linux:

#!/bin/bash
GREEN=$(tput setaf 2)
RED=$(tput setaf 1)
YELLOW=$(tput setaf 3)
NOCOL=$(tput sgr0)

echo "This works in Linux...."
echo "This is ${GREEN} Green${NOCOL} in Green"
echo "This is ${RED} Red${NOCOL} in Red"
echo "This is ${YELLOW} Yellow${NOCOL} in Yellow"
echo ""

So on Solaris this would be done like this (And this also works on Linux):

#!/bin/bash
GREEN="\033[0;32m"
RED="\033[0;31m"
YELLOW="\033[0;33m"
NOCOL="\033[0m"

echo "This works in Linux and Solaris...."
echo -e "This is ${GREEN} Green${NOCOL} in Green"
echo -e "This is ${RED} Red${NOCOL} in Red"
echo -e "This is ${YELLOW} Yellow${NOCOL} in Yellow"

    

So I guess I am going to have to stick to the second method to make my stuff work across platforms - From the script bits above you can see that a font effect is turned on with a code and you will have you will have to use a reset code "\033[0m" to turn it back off. The \033 ANSI escape sequence has a lot of codes to go in hand with it to do all sort of clever effects.

    echo -e "\033[31;1;4mHello\033[0m"

This example above has a comma separated list of codes so you got 31 for red, 1 for bold and 4 for underline and all this is cleared again with 0

This is a table that lists all the effect codes:

Code Effect Note
0 Reset / Normal all attributes off
1 Bold or increased intensity
2 Faint (decreased intensity) Not widely supported.
3 Italic Not widely supported. Sometimes treated as inverse.
4 Underline
5 Slow Blink less than 150 per minute
6 Rapid Blink MS-DOS ANSI.SYS; 150+ per minute; not widely supported
7 [[reverse video]] swap foreground and background colors
8 Conceal Not widely supported.
9 Crossed-out Characters legible, but marked for deletion. Not widely supported.
10 Primary(default) font
11–19 Alternate font Select alternate font n-10
20 Fraktur hardly ever supported
21 Bold off or Double Underline Bold off not widely supported; double underline hardly ever supported.
22 Normal color or intensity Neither bold nor faint
23 Not italic, not Fraktur
24 Underline off Not singly or doubly underlined
25 Blink off
27 Inverse off
28 Reveal conceal off
29 Not crossed out
30–37 Set foreground color See color table below
38 Set foreground color Next arguments are 5;<n> or 2;<r>;<g>;<b>, see below
39 Default foreground color implementation defined (according to standard)
40–47 Set background color See color table below
48 Set background color Next arguments are 5;<n> or 2;<r>;<g>;<b>, see below
49 Default background color implementation defined (according to standard)
51 Framed
52 Encircled
53 Overlined
54 Not framed or encircled
55 Not overlined
60 ideogram underline hardly ever supported
61 ideogram double underline hardly ever supported
62 ideogram overline hardly ever supported
63 ideogram double overline hardly ever supported
64 ideogram stress marking hardly ever supported
65 ideogram attributes off reset the effects of all of 60-64
90–97 Set bright foreground color aixterm (not in standard)
100–107 Set bright background color aixterm (not in standard)

    

The table below lists the basic 8bit color table which should be sufficient for most cases - there are plenty of other sources to give you 256 colours but in most cases that would not be required

Edited on: Thu, Dec 05, 2024 16:29

Posted in HowTo (RSS), Shell Scripting (RSS), System - AIX (RSS), System - Linux (RSS), System - Solaris (RSS)

Compare versions in bash - vercomp {}

Posted on Fri, Jun 24, 2022 at 17:23 by Hubertus A. Haniel

I have taken this from https://stackoverflow.com/a/4025065/1763937 and it can also be found at https://github.com/f-o-a-m/cliquebait/blob/master/vercomp.bash

I have put a copy of it here for my own reference mostly as I think this is a really good pice of code and I have used it in a few scripts now:

    
#!/bin/bash
vercomp () {
    if [[ $1 == $2 ]]
    then
        return 0
    fi
    local IFS=.
    local i ver1=($1) ver2=($2)
    # fill empty fields in ver1 with zeros
    for ((i=${#ver1[@]}; i<${#ver2[@]}; i++))
    do
        ver1[i]=0
    done
    for ((i=0; i<${#ver1[@]}; i++))
    do
        if [[ -z ${ver2[i]} ]]
        then
            # fill empty fields in ver2 with zeros
            ver2[i]=0
        fi
        if ((10#${ver1[i]} > 10#${ver2[i]}))
        then
            return 1
        fi
        if ((10#${ver1[i]} < 10#${ver2[i]}))
        then
            return 2
        fi
    done
    return 0
}

testvercomp () {
    vercomp $1 $2
    case $? in
        0) op='=';;
        1) op='>';;
        2) op='<';;
    esac
    if [[ $op != $3 ]]
    then
        echo "FAIL: Expected '$3', Actual '$op', Arg1 '$1', Arg2 '$2'"
    else
        echo "Pass: '$1 $op $2'"
    fi
}

# Run tests
# argument table format:
# testarg1   testarg2     expected_relationship
echo "The following tests should pass"
while read -r test
do
testvercomp $test
done << EOF
1            1            =
2.1          2.2          <
3.0.4.10     3.0.4.2      >
4.08         4.08.01      <
3.2.1.9.8144 3.2          >
3.2          3.2.1.9.8144 <
1.2          2.1          <
2.1          1.2          >
5.6.7        5.6.7        =
1.01.1       1.1.1        =
1.1.1        1.01.1       =
1            1.0          =
1.0          1            =
1.0.2.0      1.0.2        =
1..0         1.0          =
1.0          1..0         =
EOF

echo "The following test should fail (test the tester)"
testvercomp 1 1 '>'

Now when you run the code:

$ . ./vercomp
The following tests should pass
Pass: '1 = 1'
Pass: '2.1 < 2.2'
Pass: '3.0.4.10 > 3.0.4.2'
Pass: '4.08 < 4.08.01'
Pass: '3.2.1.9.8144 > 3.2'
Pass: '3.2 < 3.2.1.9.8144'
Pass: '1.2 < 2.1'
Pass: '2.1 > 1.2'
Pass: '5.6.7 = 5.6.7'
Pass: '1.01.1 = 1.1.1'
Pass: '1.1.1 = 1.01.1'
Pass: '1 = 1.0'
Pass: '1.0 = 1'
Pass: '1.0.2.0 = 1.0.2'
Pass: '1..0 = 1.0'
Pass: '1.0 = 1..0'
The following test should fail (test the tester)
FAIL: Expected '>', Actual '=', Arg1 '1', Arg2 '1'    
  
Edited on: Mon, Oct 10, 2022 12:43

Posted in Shell Scripting (RSS)

function cleanexit {} - Clean your shit!

Posted on Mon, Jun 20, 2022 at 11:42 by Hubertus A. Haniel

When writing shell scripts in bash that create temporary files I prefer to stick a clean exit function at the top of the script that runs the clean up no matter how the script exits - this should even remove files when the script got interrupted:

	function cleanexit
{
rm -f /var/tmp/tmpfile
}
trap cleanexit INT QUIT TERM EXIT

Let me know if you have a better idea!

Edited on: Wed, Aug 02, 2023 14:36

Posted in HowTo (RSS), Shell Scripting (RSS), System - AIX (RSS), System - Linux (RSS), System - Solaris (RSS)

Welcome - Notes from a Linux/Unix Engineer

Posted on Tue, Jun 01, 2010 at 11:11 by Hubertus A. Haniel

I used to collect notes documents and HOWTO's at http://www.rootunix.org  which are now archived at http://www.unixcook.com/old-unix-docs/  as it was difficult to maintain and I got lazy with it. I have come across a cross-platform blog software called Thingamablog   which is written in Java so it works on Windows and Unix and I am hoping that it will enable me to publish useful notes at a quicker pace with not a lot of messing around.

We will see how successful that will be....

Posted in Automation (RSS), HowTo (RSS), Packaging (RPM) (RSS), Shell Scripting (RSS), System - AIX (RSS), System - Apple / OSX (RSS), System - Linux (RSS), System - Solaris (RSS), System - Windows (RSS), Virtualization (RSS)