9

I'm trying to pull two numerical values out of a string and assign them to variables using awk (gawk is what I'm using specifically). I want to pull the major and minor version numbers out of a tmux version string into awk variables, e.g.:

  • input: tmux 2.8; maj == 2 and min == 8
  • input: tmux 1.9a; maj == 1 and min == 9
  • input: tmux 2.10; maj == 2 and min == 10

Assuming my input comes from tmux -V on stdin, I currently have the following:

tmux -V | awk '{
                  maj = +gensub(/([0-9]+)\..*/, "\\1", "g", $2);
                  min = +gensub(/.*\.([0-9]+).*/, "\\1", "g", $2);
                  # ...do something with maj and min...
               }'

This works, but as many users of tmux know, using if-shell in the .tmux.conf file (where I hope to use this stuff) can easily lead to really long lines in the config file, so I'm wondering if there's a way to combine these two variable assignments into one statement to save space...or any other way to glean these two variables from the input and save space.

I'm thinking of something like:

awk '{ maj, min = +gensub(/([0-9]+)\.([0-9]+).*/, "\\1 \\2", "g", $2); }'

...kind of like in Python, but that particular syntax doesn't exist in awk. Is there anything else that's possible?

Note that readability isn't really a concern, just length.

9

Note that gensub is a gawk extension, it won't work with any other awk implementation. Also note that the + unary operator doesn't force numeric conversion in all awk implementations, using + 0 is more portable.

Here you could do:

tmux -V | awk -F '[ .]' '{maj = $2+0; min = $3+0; print maj, min}'

If you don't mind using GNU awk extensions, you could also do:

tmux -V | awk -v FPAT='[0-9]+' '{maj = $1; min = $2; print maj, min}'
  • Thanks for the additional explanations on compatibility! – villapx Mar 21 at 20:45
13

Since you're using GNU awk, you can use the 3-arg form of match() to store multiple capturing groups:

awk '
    match($0, /([0-9]+)\.([0-9]+)/, m) {maj=m[1]; min=m[2]; print maj, min}
' <<END
tmux 2.8
tmux 1.9a
tmux 2.10
END
2 8
1 9
2 10

https://www.gnu.org/software/gawk/manual/html_node/String-Functions.html

5

You can split the version into an array:

awk '{ split($2, ver, /[.a-z]/) }'

then use ver[1] instead of maj, ver[2] instead of min.

Adding a-z to the separator removes any lowercase letter from the version number. (The other solutions are better here since they explicitly extract numbers.)

3

Another user posted this answer, and it later was deleted. I thought it was useful:

Using the split() function, split the version string into an array ver, then access ver[1] and ver[2] rather than maj and min, respectively (or simply store the values in those variables):

tmux -V | awk '{ split($2, ver, /[.a-z]/); print ver[1], ver[2] }'

The plus here is that split() isn't a gawk extension (though its optional fourth argument seps is).

  • +1 but why use /[.a-z]/ as the third (field separation) argument of the split string function, instead of just "." ? – Cbhihe Mar 22 at 7:22
  • 2
    @Cbhihe see the explanation on my answer (which I undeleted since villapx thinks it’s useful, thanks villapx!). – Stephen Kitt Mar 22 at 8:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.