0

I am using the following sed command(with word boundary):

sed "7 s/\<<Filevalue=.*/>\>/<Filevalue="true"/>/" < config.xml

And I am getting this error:

sed: command garbled: 7 s/\<<Filevalue=.*/>\>/<Filevalue="true"/>/

I tried escaping special characters but still getting same error:

sed "7 s/\<\<Filevalue=.*\/\/\>\>/\<Filevalue=\"true\"\/\>/" < config.xml

What have I done wrong?

EDIT:

This is a dummy XML. Values of Filevalue may vary.

XML Content:

<Filevalue="false">
<Filevalue="false">
<Filevalue="false">
<Filevalue="false">
<Filevalue="false">
<Filevalue="false">
<Filevalue="false">
Menon
  • 305
  • Can you quote the snippet out of your config.xml. That doesn't look like valid XML? – Sobrique May 07 '15 at 10:37
  • I dont think this has anything to do with the XML. Its just a dummy xml I created for testing. – Menon May 07 '15 at 10:48
  • Point is pretty inherently, XML is a data format that is not well suited to regex parsing. But XML parsers can do it very easily. – Sobrique May 07 '15 at 10:49
  • OK, thanks for including it. That isn't valid XML. I'd suggest that you're going down the wrong road using it in your 'dummy XML' file. – Sobrique May 07 '15 at 10:52
  • See http://unix.stackexchange.com/q/129059 – Stéphane Chazelas May 07 '15 at 11:05
  • @Sobrique, I know this is not a well formatted xml. But I am using sed command and not any XML parser which is why I said the error is not related to XML format. I cannot use XML parser here hence I have to stick with regex. So, can you point out what has caused the error? – Menon May 07 '15 at 11:10

3 Answers3

1

You have to backslash the slashes that don't work as separators, too, or use a different separator:

sed "7 s%\<<Filevalue=.*/>\>%<Filevalue="true"/>%"

Also, you can't include double quotes in double quotes without backslashing them, or switch to single quotes.

Moreover, a word can't start with a <, so \<< never matches.

choroba
  • 47,233
1

What you have done wrong is you're trying to parse XML with a regular expression. This is a bad idea - it sometimes works, but it makes brittle code. XML has a specification that allows for linefeeds, whitespace and tag nesting - all things that regex handle very badly.

The real answer is 'use a parser'.

I would suggest perl and XML::Twig as options - there are others though:

use strict;
use warnings;

use XML::Twig;

my $twig = XML::Twig->new(
    'pretty_print'  => 'indented',
    'twig_handlers' => {
        'File' => sub { $_->set_att( 'value', 'true' ) }
    }
);

$twig->parsefile('config.xml');    
$twig->print;

I have made certain assumptions about the content of your XML - if you're prepared to give a more extensive example, I'll double check and make sure this works as indented.

Edit:

Based on the snippet you posted - that isn't valid XML, so disregard the above. I would still suggest though that you don't use something that looks a bit like XML, called output.xml because that's a road to all sorts of pain and woe.

My code above will work with:

<xml>
   <File value="false"/>
   <File value="false"/>
   <File value="false"/>
   <File value="false"/>
   <File value="false"/>
   <File value="false"/>
   <File value="false"/> 
</xml>

You can check XML validity here: http://www.xmlvalidation.com/index.php?id=1&L=0

If we leave aside the fact that it's not XML - this works:

#!/usr/bin/perl
use strict;
use warnings;

while ( <DATA> ) {
    #amend just line 7
   if ( $. == 7 ) { s,<Filevalue=".*">,<Filevalue="true">,; }
   print;
}
__DATA__
<Filevalue="false">
<Filevalue="false">
<Filevalue="false">
<Filevalue="false">
<Filevalue="false">
<Filevalue="false">
<Filevalue="false">

Which you can one-liner by:

perl -nle 'if ( $.==7) {s,<Filevalue=".*">,<Filevalue="true">,g;} print;' notxml.txt
Sobrique
  • 4,424
0

choroba is mostly right ... but he's misleading about the double-quotes: that's not a problem for sed, but it is for the shell.

You only need to escape * [ ] \ . and the delimiter (by default /). In your case, I believe this would work best:

sed '7s%<<\([^>]*\)>>%<\1>%' file

If it works, use the -i option to replace it in the file.

Explanation:

  • The \( \) group an expression and is replaced on the right-hand-side with \
  • The [^>]* gobbles up all the characters until the next right-angle-bracket.
  • So anything within the incorrect double-brackets will be replaced with the same expression within one. Note, this will happen only once on line 7 unless you append the g flag to the s command.
Otheus
  • 6,138