bashshellparsing

How to capture a portion of a version number stored in a variable in a shell script


I am attempting to parse some data in a bash script and test the second part of a version number. Here is some example text, stored in a variable called myinfo:

Application 2021:

Version: 16.3.2.151
--
Application 2020:

Version: 15.1.3.302

I only need to capture the second part of the 2021 version that starts with 16 (3 in this case) and test if it's 3 or greater.

I have tried many things from various answers around the web that seem related, without success.

For example, the closest I got was using the regex (?:\b16\.)(\d) works to find 16.3 on regexr but I hadn't figured out how to capture just the 3 (probably easy if I knew regex better).

UPDATE:

Thanks to Paul Hodges for his concise answer. The background is I need to find the exact version of Adobe InDesign a user has on their system. 16.3 and above require different behavior in the remainder of the script. This could work for any situation where you needed to know an application's version number. Here is the final script, utilizing the solution I chose:

#!/bin/bash

# Ask system_profiler for information about all the installed applications
#  then use fgrep to pull out the line, and the 2 lines after, that starts with Adobe InDesign 2021
v=$(system_profiler SPApplicationsDataType | fgrep -A 2 ' Adobe InDesign 2021')

echo ${v}
#    Adobe InDesign 2021:
#
#      Version: 16.3.2.151

# Strip everything up to the first .
v="${v#*.}"
# Strip everything after the first . of the remaining text
v="${v%%.*}"

echo "${v}"
# 3

# Test if it is greater or equal to 3
if [[ "${v}" -ge 3 ]]; then
    echo Its 3 or greater
else
    echo Less than 3
fi

Solution

  • Parameter parsing can do this in a couple steps without running a subprocess.

    Assuming

    x="Application 2021:
    
    Version: 16.3.2.151
    --
    Application 2020:
    
    Version: 15.1.3.302"
    

    Then

    x="${x#*.}"
    

    strips everything from the front through the first dot, and

    x="${x%%.*}"
    

    strips everything from the (now) first dot to the end.

    echo $x
    3
    

    So if your data is in x,

    x="${x#*.}"; echo ${x%%.*}
    

    will output 3.

    If you want more precise parsing, activate extended globbing.

    $: shopt -s extglob
    $: y="${x//*Application+([[:space:]])2021:+([[:space:]])Version:+([[:space:]])+([0-9])./}"
    $: echo "${y%%.*}"
    3
    

    Just remember this is globbing, not real regex parsing.
    For that, use sed or awk, though this will do the job just fine.

    For more detailed info on globbing, c.f. https://mywiki.wooledge.org/glob
    For more on basic parameter parsing, c.f. https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html