0

This question already has an answer here:

the following useful find command , print the value from Name tag

find /tmp -type f -name '*.xml' -exec grep -o -P '(?<=<Name>).*(?=</Name>)' {} \;

the problem is in case we have couple xml files under /tmp then we never know which xml file have the Name tag

or in other words this find syntax will print the value of Name

but without the xml file name

please advice how to print the file name when grep matched the:

(?<=<Name>).*(?=</Name>)

marked as duplicate by don_crissti, Jeff Schaller, Romeo Ninov, Wouter Verhelst, G-Man Says 'Reinstate Monica' Jan 19 '18 at 0:29

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

1

grep will always output the filename of the file containing the match if more than one file is given on the command line. If you only pass it one file, no filename will be printed.

To force always printing the filename along with the actual match, add /dev/null as an extra file to grep in:

find /tmp -type f -name '*.xml' -exec grep -o -P '(?<=<Name>).*(?=</Name>)' {} /dev/null \;

Or, for potentially fewer invocations of grep, use find -exec grep ... {} + instead:

find /tmp -type f -name '*.xml' -exec grep -o -P '(?<=<Name>).*(?=</Name>)' /dev/null {} +

At least GNU grep as well as grep on OpenBSD and FreeBSD also support the -H flag to always print the filename, even if only one file is given. Since you used grep -P, you're probably using GNU grep anyway.

  • or with GNU grep, just use the -H aka --with-filename option. e.g. grep -H -o -P ..... – cas Jan 18 '18 at 8:19
1

You simply give greps "-H" parameter, then the filename will always be printed, even if there is only one file to grep from (as in your case).

  • -H is an extension to the standard grep supported by GNU grep and a few other implementations. – Kusalananda Jan 18 '18 at 8:23
  • 1
    On linux, I suppose the chances that the OP is using GNU grep, are quite high. – Gerard H. Pille Jan 18 '18 at 8:27
1

Note, grep is not the right tool for parsing xml/html files(documents) and won't give a robust and solid solution. Use a "proper" xml/html parsers like xmlstarlet:

find /tmp -type f -name '*.xml' -exec xmlstarlet sel -t -m "//Name" -f -n {} \;
  • xmlstarlet sel -t -m "//Name" -f -n - will print input file name (ensured by option -f) only if input xml document matches (-m) XPATH expression "//Name"
  • xmlstarlet not installed on my machine can you change it to xmllint – yael Jan 18 '18 at 8:23
  • I guess option to do the same approach with xmlinit cant be done? – yael Jan 18 '18 at 8:51
  • @yael, xmllint is not able to print its input filename as the only output (only within a debug-trace). It's doable and I have such solution but it requires a subshell invocation, just a little bit longer than the above approach. So if you need it - I have it – RomanPerekhrest Jan 18 '18 at 8:54
0

If you don't mind that the filename is printed after the found lines, there's always finds "-print" option:

find /tmp -type f -name '*.xml' -exec grep -o -P '(?<=<Name>).*(?=</Name>)' {} \; -print

Not the answer you're looking for? Browse other questions tagged or ask your own question.