I have the following file ( file1 )

more file1

<?xml version="1.0" encoding="UTF-8"?>

 <app name="UAT/ECC/Global/MES/1206/MRP-S23"  ear="UAT/ECC/Global/MES/1206/MRP-S23.ear" xml="UAT/ECC/Glal/ME/120/MRP- S23.xml"/>
  <app name="OQ/ediedbn/adSFSF/adSFSF-CL" ear="OQ/ebn/aSF/adSF- CL.ear" xml="OQ/ediedbn/adSFSF/adSSF-CL.xml"/>
 <app name="OQ/ediedbn/adaEBS/adOrBS-HR-CL"  ear="OQ/ediedbn/adOraS/araEBS-HR-CL.ear" xml="OQ/eddbn/aOraEBS/adOEBS-   HR-CL.xml"/>
<app name="UAT/CZ/LIMS/T068_01/LIMS-QA-S03" ear="UAT/CZ/LIS/T068_01/LIS-QA-S03.ear" xml="UAT/CZ/LIMS/T068_01/LIMS-QA-S03.xml"/>

and this are the examples lines that I need to match on file1

more file2


what is the best approach in perl one liner syntax in order to match the lines from file2 on file1 ( and ignore the backslash and other unusual characters )

I tried this but not work


 perl -pe '/(^|\s)\Q$ENV{a}\E(\s|$)/'  file1

Your attempt had several issues:

  1. perl -pe prints all lines - you either need to delete non-matching lines, or use -n and explicit print
  2. matched strings are preceded with quotes but you check for \s
  3. For testing it is useful to show file1 with some lines matching file2 :)

So this will work:

a="UAT/CZ/LIMS/T068_01/LIMS-QA-S03" perl -ne '/"\Q$ENV{a}\E"/ && print' file1

To do all the matching in one line, you can do:

perl -ne 'BEGIN { open(F2, shift); $re=join("|", map {chomp($_); "\"\Q${_}\E\"";} <F2>);} /$re/ && print' file2 file1
|improve this answer|||||

This is XML. Regular expressions are a bad fit for XML, for all they look like they should work.

This is because XML is contextual, and regular expression aren't. And XML has a bunch of formatting variances which are semantically identical, but don't match the same regex.

Although - it looks like none of your 'second file' entries match your first file in your example. I'm going to guess that you're wanting to match the 'name' field of the XML though. (You should avoid 'match any attribute' if you can).


use strict;
use warnings;

#dumper is only needed for the 'print Dumper' line below
#for debugging. Both can safely be removed. 
use Data::Dumper;
use XML::Twig;

open ( my $match_file, '<', 'file2' ) or die $!;
chomp ( my @matches = <$match_file> ); 
my %lookup = map { $_ => 1 } @matches; 

#or if you want a more pithy one that IMO is a bit harder to understand. 
#my %lookup = map { s/[\r\n]+//gr => 1 } <$match_file>;

print Dumper \%lookup; 

my $twig = XML::Twig -> new -> parsefile ( 'file2' ); 

#xpath is XMLs equivalent of regex, but it's 
#more suited to node and attribute matching. 
foreach my $app ( $twig -> get_xpath ( '//app' ) ) {
   $app -> print if $lookup{$app->att('name')};
   #Alternatively extract a single field. 
   print "XML: ", $app -> att('xml'),"\n";

As a one liner? Honestly, I wouldn't, if you want to do both the reading in of the matches -and- the search/print.

But for a single element, I'd perhaps go with:

a="UAT/CZ/LIMS/T068_01/LIMS-QA-S03" perl -MXML::Twig -e 'XML::Twig -> new ( twig_handlers => { 'app' => sub { $_ -> print if $_ -> att('name') eq $ENV{'a'} } } ) -> parse ( { do {local $/; <> } )'

But honestly - I'd stick with writing it out 'long form' rather than trying to enact some magic in a single line - if you try and read all your patterns, you end up with an inefficient algorithm, and if you try and do them all then you're doing a double file read and data structure in the same one liner, and that's just messy.

|improve this answer|||||

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.