hxd1011
hxd1011

Reputation: 915

why grep does not return all pari of numbers?

Executing echo "123456" | grep -Eo "[[:digit:]]{1,2}" will return tree pairs, 12, 34, 56. Why it does not return 12, 23, 34, 45, 56?

Upvotes: 1

Views: 78

Answers (2)

David C. Rankin
David C. Rankin

Reputation: 84609

While you already have a valid answer, if your shell is bash (or another advanced shell that allows string indexes), it would be far more efficient to use bash's built-in string indexing and a C-style for loop to output each pair in a given string rather than spawning a separate subshell on each loop iteration created by calling sed.

Bash string indexing allows you to access len characters within a string beginning at start index (where the valid indexes are 0 - len-1) using the form:

${var:$start:$len}

Combined with a C-style for loop looping over each index i in the string beginning at index 1 (the 2nd character) and outputting the pair of characters created by:

"${var:$((i-1)):2}"

A short example would be:

str=123456

for ((i = 1; i < ${#str}; i++)); do 
    echo "${str:$((i-1)):2}"
done

Example Use/Output

$ str=123456; \
for ((i = 1; i < ${#str}; i++)); do echo "${str:$((i-1)):2}"; done
12
23
34
45
56

Look things over and let me know if you have further questions.

Upvotes: 1

ingroxd
ingroxd

Reputation: 1025

Your regular expression is not printing all of 5 pairs of numbers because you are asking only for three.

Your regex is the equivalent of [0-9][0-9] and will check that particular match starting from left; so if you have 123456 the steps would be something like:

  • 1 -> Match? No; don't print anything.
  • 12 -> Match? Yes; print it.
  • 3 -> Match? No; don't print anything.

And so on...

Note that it doesn't start again after a match, otherwise it would match 12 over and over again...

You can use other solutions for your problem.

For example, if you need all pairs in that string you can use a function that take the first two numbers; cut the first one and check again, until the string is too short...

#!/bin/bash
check_pairs() {
  local str="${1}"
    if [ "${#str}" -ge 2 ]; then
      printf "%s\n" "${str}" | sed -e "s/^\([0-9][0-9]\).*$/\1/"
      check_pairs "${str#?}"
    fi  
}
check_pairs "123456"
exit 0

Probably there are other solutions (better, faster, stronger), but I cannot think of them right now.

Upvotes: 2

Related Questions