Remove the first match only in a file using sed

I'm trying to remove the first match only of 2Z694 from an xml file and replace with a blank

File Example:

</Phoenix_Response_Data>
<Bundle_Name_Primary>2Z694</Bundle_Name_Primary>
<Bundle_Name>2Z694</Bundle_Name>
</Phoenix_Response_Data>

tried using:

 sed -e 's/'2Z694'/''/1' 

but this blanks out all instances of 2Z694.

Does it have to be sed?

perl -0pe 's/2Z694//' file.xml
sed '/2Z694/,$ {1,1 s/2Z694/ /}' file
</Phoenix_Response_Data>
<Bundle_Name_Primary> </Bundle_Name_Primary>
<Bundle_Name>2Z694</Bundle_Name>
</Phoenix_Response_Data>

Thanks for the reply Rudi but your suggestion returns an error

sed: 1: "/2Z694-00609/,$ {1,1 s/ ...": bad flag in substitute command: '}'

Below is the file and I'm trying to strip out the first and only match of 2Z694-00609

<?xml version="1.0" encoding="UTF-8"?><SI_Response><SI_Response_Header><Command_Name>Comm.Get.BundleList</Command_Name><Supported>SUPPORTED</Supported><Responses_Sent>1</Responses_Sent><Responses_Expected>1</Responses_Expected><App_Name>phoenixd-7700</App_Name><Sequence_Number>1</Sequence_Number><Error_Code>0</Error_Code><Error_Msg></Error_Msg></SI_Response_Header><SI_Response_Data>
<Phoenix_Response>
<Phoenix_Response_Header version="1.0"></Phoenix_Response_Header>
<Phoenix_Response_Data>
<Bundle_Name>2Z694-00609</Bundle_Name>
<Bundle_Name_Primary>2Z694-00609</Bundle_Name_Primary>
</Phoenix_Response_Data>
</Phoenix_Response>
</SI_Response_Data></SI_Response>

This is what I have tried ...

BundleName=`cat /Phoenix/Configuration/bundlelist.txt | grep -m 1 "2Z694" | awk -F "[>,<]" '{print$3}'`

echo Bundlelist found is $BundleName

cp -f /Phoenix/Configuration/bundlelist.txt /Phoenix/bundlelist1.txt

sed '/'2Z694-00609'/,$ {1,1 s/'$2Z694-00609'/ /}' /Phoenix/bundlelist1.txt > /Phoenix/Configuration/bundlelist.txt

Any other ideas, thanks again ...

With awk:

awk '!p{p=sub("2Z694-00609",x)}1' file
2 Likes

Must be a different sed version:

sed '/2Z694-00609/,$ {1,1 s/2Z694-00609/ /}' file
<?xml version="1.0" encoding="UTF-8"?><SI_Response><SI_Response_Header><Command_Name>Comm.Get.BundleList</Command_Name><Supported>SUPPORTED</Supported><Responses_Sent>1</Responses_Sent><Responses_Expected>1</Responses_Expected><App_Name>phoenixd-7700</App_Name><Sequence_Number>1</Sequence_Number><Error_Code>0</Error_Code><Error_Msg></Error_Msg></SI_Response_Header><SI_Response_Data>
<Phoenix_Response>
<Phoenix_Response_Header version="1.0"></Phoenix_Response_Header>
<Phoenix_Response_Data>
<Bundle_Name> </Bundle_Name>
<Bundle_Name_Primary>2Z694-00609</Bundle_Name_Primary>
</Phoenix_Response_Data>
</Phoenix_Response>
</SI_Response_Data></SI_Response>
sed --version
sed (GNU sed) 4.2.2

Thanks Franklin, awk works as expected. Rudi I'm running off Mac OS X 10.8 so see version different. Thanks again

Simple, only delete in the range including the first pattern:

sed '
  1,/pattern/{
    s/pattern/new/
    }
 ' in_file >out_file

It is even easier than that: just quit sed after the first match:

sed '/<pattern>/ {;s/<pattern>/<subst>/;q;}' /your/input/file

I hope this helps.

bakunin

No, that loses the tail of the file. You cannot quit.

You are right. If you need the tail, you cannot. Somehow i misread the problem statement yesterday and was under the impression that the tail wasn't important. My bad.

bakunin

As long as the first occurrence of the pattern isn't on the first line, otherwise it will delete two..

GNU sed can use this:

gsed '0,/pattern/{s/pattern//;}' file

or even:

gsed '0,/pattern/{s///}' file

---

Is the 1,1 an undocumented feature of GNU sed ?
Why would the first 1 become true?

In regular sed it does not work:

sed '/2Z694/,$ { 1,1 s/2Z694//;}' infile3104
</Phoenix_Response_Data>
<Bundle_Name_Primary>2Z694</Bundle_Name_Primary>
<Bundle_Name>2Z694</Bundle_Name>
</Phoenix_Response_Data>

It only works if the first line number is the actual line number

$ sed '/2Z694/,$ { 2,1 s/2Z694//;}' file
</Phoenix_Response_Data>
<Bundle_Name_Primary></Bundle_Name_Primary>
<Bundle_Name>2Z694</Bundle_Name>
</Phoenix_Response_Data>

But that would of course not be useful...

I ran into this a few times before, and I was surprised as well. Mayhap it's only GNU sed that does this. It seems starting over counting lines in the {...}block, but the line no. printed by "=" is the real file's one. And, it needs the range "1,1". Just the "1" address doesn't work.

I don't think it starts over counting. It looks more like a bug to me:

$ gsed '/2Z694/,$ { 1,1 s/2Z694//;}' file
</Phoenix_Response_Data>
<Bundle_Name_Primary></Bundle_Name_Primary>
<Bundle_Name>2Z694</Bundle_Name>
</Phoenix_Response_Data>
$ gsed '/2Z694/,$ { 2,1 s/2Z694//;}' file
</Phoenix_Response_Data>
<Bundle_Name_Primary></Bundle_Name_Primary>
<Bundle_Name>2Z694</Bundle_Name>
</Phoenix_Response_Data>
$ gsed '/2Z694/,$ { 3,1 s/2Z694//;}' file
</Phoenix_Response_Data>
<Bundle_Name_Primary>2Z694</Bundle_Name_Primary>
<Bundle_Name></Bundle_Name>
</Phoenix_Response_Data>

Yes, strange enough. It doesn't care what range it is, as long as the begin is below the line number. Doesn't look like sth you should rely upon.

Regular sed can avoid first line problems and double maching test but needs a complex tail copier:

sed '
  s/pattern/new/
  t loop
  b
  :loop
  $b
  N
  P
  s/.*\n//
  b loop
 ' in_file >out_file

Once the first s fires, flow transfers into loop to copy the tail out. It's a shame sed does not have a variation on D to delete the first line or all but the last line and leave the buffer and flow intact.