jchi2241
jchi2241

Reputation: 2226

Pulling version out of string with bash script

I would like to check the local version of Hugo.

$ hugo version
Hugo Static Site Generator v0.49 linux/amd64 BuildDate: 2018-09-24T10:03:17Z

What would be a safe and future-proof method to extract v0.49 from the output above with a bash script?

Upvotes: 0

Views: 63

Answers (3)

Tom Fenech
Tom Fenech

Reputation: 74615

Maybe you're better off using grep like this:

$ hugo version
Hugo Static Site Generator v0.59.0-DEV/extended linux/amd64 BuildDate: unknown
$ version=v0.59
$ hugo version | grep -q "${version//./\\.}" && echo "correct version"
correct version
$ version=v0.43
$ hugo version | grep -q "${version//./\\.}" || echo "incorrect version"
incorrect version

grep -q exits successfully if the regex matches, so can be used with shell conditional constructs. I am using a parameter expansion to replace . with \., so that the version number can be used in a regular expression (otherwise the . would match any character).

The bash docs explain how parameter expansion works (see ${parameter/pattern/string}). Basically, ${version//./\\.} globally (/) replaces a . with a \.. Two \ are required in the replacement string, because the first one escapes the second one.

Upvotes: 1

David C. Rankin
David C. Rankin

Reputation: 84561

A sed expression can be fairly general and still work so long as you version remains in the form of

v[any number of digits].[any number of digits]

To use sed, you can simply pipe the output of hugo version to your sed expression, e.g.

$ hugo version | sed 's/^.*\(v[0-9][0-9]*[.][0-9][0-9]*\).*$/\1/'

Example Use/Output

With your output that would result in:

$ hugo version | sed 's/^.*\(v[0-9][0-9]*[.][0-9][0-9]*\).*$/\1/'
v0.49

You can capture the result in a variable using command substitution, e.g.

hversion=$(hugo version | sed 's/^.*\(v[0-9][0-9]*[.][0-9][0-9]*\).*$/\1/')

Explanation of sed Expression

The breakdown of the sed expression is the normal substitution s/find/replace/ where:

  • find is:
    • ^.* - and number of characters from the beginning,
    • \( - begin a capture group to save what follows,
    • v - the character 'v',
    • [0-9][0-9]* - at least 1 digit followed by zero or more digits,
    • [.] - a decimal point (or period), followed by
    • [0-9][0-9]* - at least 1 digit followed by zero or more digits,
    • \) - end the capture group saving the captured content,
    • .*$ - all characters to the end of the string.
  • replace is:
    • \1 a single backreference to the text from the first capture group.

That is the extent of it. A normal substitution using a single backreference which will work the same for v0.49 as it will for v243.871.

Upvotes: 1

Léa Gris
Léa Gris

Reputation: 19555

I'd probably use Bash's builtin read like this:

read -r _ _ _ _  hugo_version _ < <(hugo version)

Upvotes: 0

Related Questions