I'm using Cygwin so I've been reviewing POSIX regex info.

I'm trying to search through an xml file for a string and I keep getting the entire line but cannot seem to narrow the results to the few characters I'm looking for.

The file (file1) has many instances of:

<!ENTITY abc123456 SYSTEM "../blah/abc123456.xyz" NDATA xyz>
<!ENTITY abc123457 SYSTEM "../blah/abc123457.xyz" NDATA xyz>
<!ENTITY abc123458 SYSTEM "../blah/abc123458.xyz" NDATA xyz>

The grep results list the entire line but I'm trying to narrow the results to:


The following successfully give me the lines:

grep -E abc[[:digit:]] file1
grep abc[0-9] file1
grep "abc[[:digit:]]" file1

Since what I'm looking for is not at the beginning or end of a line, ^ and $ don't seem to be useful. Not sure how to anchor what I'm searching for. I've tried quite a few other variations of using grep without success.

  • 2
    XPath or otherwise XML aware tools are usually slightly better than grep on XML...
    – thrig
    Commented Feb 25, 2017 at 16:38
  • 1
    AFAIK outputing only the matching portion of the line is controlled by the -o command line option, rather than by anchoring the regular expression. Or am I misunderstanding your question? Commented Feb 25, 2017 at 16:41
  • Sounds like you totally understand it. That sounds exactly like what I'm looking for... will try. Thx!
    – regexnoob
    Commented Feb 25, 2017 at 16:42
  • OMG! That's it! So, I've tried using the {6} with the [0-9] or with the [[:digit:]] but that doesn't seem to help. Now my output is abc1... but that's way closer than I was. Thx again.
    – regexnoob
    Commented Feb 25, 2017 at 16:44
  • 2
    Both grep -Eo 'abc[0-9]{6}' and grep -Eo 'abc[[:digit:]]{6}' appear to work for me in Cygwin64 with GNU grep 2.21 Commented Feb 25, 2017 at 17:07

2 Answers 2


There must be more elegant solutions (perhaps grep -P is one?), but you can use sed to simulate grep and get the strings you want in cases when a simple grep -o is not enough:

sed -nr 's/.*SYSTEM "..\/blah\/([^"]*).*/\1/p'

This will basically match the whole string, and then replace it entirely with the substring you were looking for.

  • So, I remember sed is a stream editor. I really didn't want to replace it with the substring I was looking for... instead, need to pipe it to a list.
    – regexnoob
    Commented Feb 25, 2017 at 17:06
  • "I really didn't want to replace it with the substring I was looking for" - You listed lines in the form of "abc123456.xyz" as your desired output. This is exactly what this sed command does, it takes the entire XML file as the input and gives your file names as the output.
    – undercat
    Commented Feb 25, 2017 at 17:12
  • Ahhhh... thank you. I misunderstood. Thought that means it was writing it back to the file. :) Will try again.
    – regexnoob
    Commented Feb 25, 2017 at 17:19
  • You can write back to the file with -i, but by default it sends the output to STDOUT.
    – undercat
    Commented Feb 25, 2017 at 17:19

The grep command prints lines containing a match. No matter what pattern you use to match a part of the line, grep prints the whole line.

GNU grep, which is the version included in Cygwin, has an option to display only the part of the line matched by the pattern: -o.

grep -o 'abc[0-9][^"]*' file1

You can add \b at the beginning of the pattern to only match after whitespace or punctuation, i.e. to avoid matching /fooabc123.xyz. If you want to match specifically after a / or ", the punctuation character will be included in the output; you can avoid that with a lookbehind assertion which is available in Perl regex syntax.

grep -o -P '(?<=[/"])abc[0-9][^"]*' file1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .