2

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:

abc123456.xyz
abc123457.xyz
abc123458.xyz

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 Feb 25 '17 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? – steeldriver Feb 25 '17 at 16:41
  • Sounds like you totally understand it. That sounds exactly like what I'm looking for... will try. Thx! – regexnoob Feb 25 '17 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 Feb 25 '17 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 – steeldriver Feb 25 '17 at 17:07
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 Feb 25 '17 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 Feb 25 '17 at 17:12
  • Ahhhh... thank you. I misunderstood. Thought that means it was writing it back to the file. :) Will try again. – regexnoob Feb 25 '17 at 17:19
  • You can write back to the file with -i, but by default it sends the output to STDOUT. – undercat Feb 25 '17 at 17:19
0

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

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.