1

After few hours of disappointed searching I can't figure this out.

I am piping to grep input, what I want to get is first occurrence of any digit.

Example:

nmcli --version
nmcli tool, version 1.1.93

Pipe to grep with regex

nmcli --version |grep -o '[[:digit:]]'

Output:

1
1
9
3

What I want:

1

Yeah there is a way to do that with another pipe, but is there "pure" single regex to do that?

beroe
  • 11,784
  • 5
  • 34
  • 79
Marko
  • 39
  • 1
  • 6
  • @trincot did you bother to try that? `^` matches the beginning of a string, not the first instance of the following pattern. – Paul L Jun 01 '16 at 20:41
  • none of the digits are at the beginning of the string, @trincot. – Paul L Jun 01 '16 at 20:48
  • `nmcli --version | awk -F '[ .]' '{print $4}'`? – Cyrus Jun 01 '16 at 21:58
  • A "pure regex" is a closed-form formula which expresses a set of strings. A pure regex doesn't search through text or extract text, etc; it answers the question "is this string in the set or not". All else is not a "pure regex". – Kaz Jun 09 '16 at 14:54

5 Answers5

3

With GNU grep:

nmcli --version | grep -Po ' \K[[:digit:]]'

Output:

1

See: Support of \K in regex

Community
  • 1
  • 1
Cyrus
  • 84,225
  • 14
  • 89
  • 153
  • Many thanks! I just have one question about it. Is regular expression metacharacter "pure" regex expression in the world? Maybe we can't do that another way, but I was hoping in something like '[[:digit:]]?' (? match 0 or 1 time). Is it possible, or this have to be done with special care of metacharacters? – Marko Jun 01 '16 at 20:58
  • If you're okay using `awk` (see other answer) instead of `grep`, we can do it in a more portable way. But, with `grep`, and without using `head -1`, this is probably the best way. Upvoting this when my vote limit resets in 2 hours :) – Will Jun 01 '16 at 21:44
1

Although you want to avoid another process, it seems simplest just to add a head to your existing command...

grep -o [[:digit:]] | head -n1
beroe
  • 11,784
  • 5
  • 34
  • 79
0
echo "nmcli tool, version 1.1.93" |sed "s/[^0-9]//g" |cut -c1
1

echo "nmcli tool, version 1.1.93" |grep -o '[0-9]' |head -1
1
P....
  • 17,421
  • 2
  • 32
  • 52
0

This can be seen as a stream editing task: reduce that one line to the first digit. Basic regex register-based referencing achieves the task:

$ echo "junk 1.2.3.4" | sed -e 's/.* \([0-9]\).*/\1/'
1

Traditionally, Grep is best for searching for files and lines which match a pattern. This is why the grep solution requires the use of Perl regex; Perl regex has features that, in combination with -o, allow grep to escape "out of the box" and be used in ways it wasn't really intended: match X, but then output a substring of X. The solution is terse, but not portable to grep implementations that don't have PCRE.

Use [0-9] to match ASCII digits, by the way. The purpose of [[:digit:]] is to bring in locale-specific behavior: to be able to match digits other than just the ASCII 0x30 through 0x39.

It's fairly safe to say that nmcli isn't going to put outs its --version using, say, Devangari numerals, like १.२.३.४.

Kaz
  • 55,781
  • 9
  • 100
  • 149
-2

You could use standard awk instead:

nmcli --version | awk 'match($0, /[[:digit:]]/) {print substr($0, RSTART, RLENGTH); exit}'

For example:

$ seq 11111 33333 | awk 'match($0, /[[:digit:]]/) {print substr($0, RSTART, RLENGTH); exit}'
1
Will
  • 24,082
  • 14
  • 97
  • 108
  • `nmcli --version | grep -o -m1 '[[:digit:]]'` It's not working but with seq it is, also `awk` example print whole line... – Marko Jun 01 '16 at 20:45
  • 1
    your `m1` suggestion does not work. Despite what the manual implies, this stops after the first *line* that matches, not after the first actual match. It only worked with your `seq 7 10` example because `seq 7 10` returns 4 separate lines, with each number 7 to 10 on a different line. – Paul L Jun 01 '16 at 20:45
  • @PaulL Everything should work properly now. I didn't test it with realistic input, sorry. – Will Jun 02 '16 at 01:08