Need help with sed command

Hi all,

I try to use sed to find something specific in a file (test.h), find the same specific term in another file (test.xml) read an attribute of it, and replace the begining of the specific term in the test.h.

Well.... an example will be beter :slight_smile:

test.h

typedef LON_STRUCT_BEGIN(LonWriteableValueFile)
{
    SCPTminSendTime cpMinSendTime;             /* sd_string("1,0,0\x80,52,2;") */
    SCPTmaxSendTime cpMaxSendTime;             /* sd_string("1,0,0\x80,49,2;") */
    SCPTmaxRcvTime cpMaxRcvTime;               /* sd_string("1,0,0\x80,48,2;") */
}

I need to find every word that begin with [space]cp and end with ;

eg: cpMinSendTime

I think I figured something. probably not pretty, but it's works.

sed -n "/[ ]cp.*[;] /{s/^.*\(cp.*[;] \).*$/\1/;p;}" test.h | sed 's/[;]//'

this output

cpMinSendTime
cpMaxSendTime
cpMaxRcvTime

so far so good.

I need to find in the test.xml file

<?xml version="1.0" encoding="utf-8"?>
<Template Name="MyTemplate">
  <Object Name="0">
    <CPs>
      <cpMinSendTime type="SNVT_time_sec" default="5"></cpMinSendTime>
      <cpMaxSendTime type="SNVT_time_sec" default="10"></cpMaxSendTime>
    </CPs>
    <SNVTs>
      <nviPercentOpen type="SNVT_lev_percent" default="0"></nviPercentOpen>
    </SNVTs>
  </Object>
</Template>

The attribute type of the cpMinSendTime.

I think I found something too using bash script

xmlOutput=`sed -n -e '/<'${file}'/p' Test.xml`
regex="type=\"(.*?)\" "
if [[ $xmlOutput =~ "type=\"(.*?)\" " ]]; then
			cpType=${BASH_REMATCH[1]}
fi

with this I found the field Type in my xml type.

When the type is found, I need to replace SCPTminSendTime in the test.h for the cpMinSendTime with SNVT_time_sec;

The result should look like this

test.h (modified)

typedef LON_STRUCT_BEGIN(LonWriteableValueFile)
{
    SNVT_time_sec cpMinSendTime;             /* sd_string("1,0,0\x80,52,2;") */
    SNVT_time_sec cpMaxSendTime;             /* sd_string("1,0,0\x80,49,2;") */
    SNVT_time_min cpMaxRcvTime;               /* sd_string("1,0,0\x80,48,2;") */
}

Wow... I hope this is clear enough for you !

1- I have only access to bintuils. (sh, awk, grep, sed etc...)
2- Is it possible to do in a sed script ?

I have to admit that i'm not familiar with all the shell scripting

I will ne some help to do this !

regards

Jonathan

It is best to use a XML tool to process XML file.

Install Perl-XML-XPath

# yum install perl-XML-XPath.noarch
or
# perl -MCPAN -e 'install XML::XPath'

Try this:

$ cat test.h
typedef LON_STRUCT_BEGIN(LonWriteableValueFile)
{
    SCPTminSendTime cpMinSendTime;             /* sd_string("1,0,0\x80,52,2;") */
    SCPTmaxSendTime cpMaxSendTime;             /* sd_string("1,0,0\x80,49,2;") */
    SCPTmaxRcvTime cpMaxRcvTime;               /* sd_string("1,0,0\x80,48,2;") */
}

$ cat test.pl
#! /usr/bin/perl
use XML::XPath;

$xp=XML::XPath->new($ARGV[0]);
$nodes=$xp->find('/Template/Object/CPs/*');
foreach $n ($nodes->get_nodelist) {
        print $n->getName(), " ", $n->getAttribute('type'), "\n";
}

$ cat test.xml
<?xml version="1.0" encoding="utf-8"?>
<Template Name="MyTemplate">
  <Object Name="0">
    <CPs>
      <cpMinSendTime type="SNVT_time_sec" default="5"></cpMinSendTime>
      <cpMaxSendTime type="SNVT_time_sec" default="10"></cpMaxSendTime>
    </CPs>
    <SNVTs>
      <nviPercentOpen type="SNVT_lev_percent" default="0"></nviPercentOpen>
    </SNVTs>
  </Object>
</Template>

$ ./test.pl test.xml | while read k v
do 
  sed -i "s/[A-Za-z][A-Za-z]*[ \t][ \t]*$k/$v $k/" test.h
done

$ cat test.h
typedef LON_STRUCT_BEGIN(LonWriteableValueFile)
{
    SNVT_time_sec cpMinSendTime;             /* sd_string("1,0,0\x80,52,2;") */
    SNVT_time_sec cpMaxSendTime;             /* sd_string("1,0,0\x80,49,2;") */
    SCPTmaxRcvTime cpMaxRcvTime;               /* sd_string("1,0,0\x80,48,2;") */
}

Hi,

Thanks for your answer, but like I specified in the first post, i can't install perl.

I agree with you that using an xml tool should be better. I will look into this path !

Jonathan

See if this works:

awk '
  NR==FNR{
    if(/^cp/)
      for(i=1;i<NF;i++)
        if($i~/type=/)
          A[$1]=$(i+1)
    next
  } 
  A[$3]{
    sub($2,A[$3])
  }
  1
' RS=\< FS="[>\"]|[ \t]*" test.xml RS="\n" FS="[ \t]*|;" test.h

Or shorter:

awk '/^<cp/{t=$2} /^type/&&t {A[t]=$2;t=x} A[$3]{sub($2,A[$3])}FNR!=NR' RS=" " FS='<|"' test.xml RS="\n" FS="[ \t]*|;" test.h

Hi,

It's works..

I have no idea what you did, but it's works

is it possible to have it explained ?

Jonathan