1

So I have a text file:

4556 4618 7843 8732
 4532 0861 1932 5122 
3478 893* 6788 6312
5440 3173 8207 0451 67886
6011 2966 7184 4668       
3678 3905 5323
  2389 4387        9336 2783  
239 235 453 3458
182 534 654 765
 4485 0721 1308 2759
46759 543 2345

I want to grep only the numbers that have 4 digits together, 4 times in a row (seperated by a space).

For example: 4556 4618 7843 8732

I am using: grep -E "([0-9]{4} [0-9]{4} [0-9]{4} [0-9]{4})" test.txt

Which shows me:

4556 4618 7843 8732
 4532 0861 1932 5122 
5440 3173 8207 0451 67886
6011 2966 7184 4668       
 4485 0721 1308 2759

Using this there is an extra line that shouldn't appear, where there is a 5th set of numbers that has 5 digits on the end.

So I used: grep -E "([0-9]{4} [0-9]{4} [0-9]{4} [0-9]{4})$" test.txt

But this only gave me two results instead of the 4 it should:

4556 4618 7843 8732
 4485 0721 1308 2759

Can someone tell me what I'm doing wrong?

  • You also appear to be missing 2389 4387 9336 2783 -- are extra spaces the eliminating factor? – glenn jackman Dec 13 '18 at 22:00
3
$ grep -E '^[[:blank:]]*[0-9]{4} [0-9]{4} [0-9]{4} [0-9]{4}[[:blank:]]*$' file
4556 4618 7843 8732
 4532 0861 1932 5122
6011 2966 7184 4668
 4485 0721 1308 2759

Your expression matches lines with four or more sets of space-delimited four-digit numbers. The parentheses don't do anything in the expression.

The expression above anchors the pattern to the start and end of the line and only allows spaces or tabs to exist before the first and after the last sets of digits.

As an alternative to using the ^ and $ anchors, you could instead use grep -x:

grep -Ex '[[:blank:]]*[0-9]{4} [0-9]{4} [0-9]{4} [0-9]{4}[[:blank:]]*'

And shortening this, just like Jeff has shown,

grep -Ex '[[:blank:]]*([0-9]{4} ){3}[0-9]{4}[[:blank:]]*'
  • This works great, exactly what I was looking for. I was forgetting to use * – ESuth Dec 13 '18 at 18:51
3

You got halfway there with the end-of-line anchor $; you just need to anchor the beginning of the line, too, with ^. Looks like you're OK with a leading space, so allow for that as well, with *:

grep -E "^ *([0-9]{4} [0-9]{4} [0-9]{4} [0-9]{4})$" test.txt

If it helps to simplify the typing (or understanding) any, you could combine the first three patterns:

grep -E "^ *([[:digit:]]{4} ){3}[[:digit:]]{4}$"

... meaning you want 3 of the quantity (4 digits followed by a space) followed by a space, then 4 digits, then EOL.

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.