Home > database >  bash script sed or awk. replace string depending on whether it is odd or even
bash script sed or awk. replace string depending on whether it is odd or even

Time:10-01

I m trying to replace a string "::" on a plain text for <b> or </b>. Depending of the first or second match without result with sed. The goal here is that the second tag </b> can be at the end of a paragraph not at the end of a line. i.e:

::Habiéndose calmado de distracciones, uno permanece completamente, 
y la naturaleza superior es vista con los ojos de la sabiduría.::

must be

<b>Habiéndose calmado de distracciones, uno permanece completamente, 
y la naturaleza superior es vista con los ojos de la sabiduría.</b>

I try it without result:

sed "s|::\(.*\)|\\<b>\1\</b>|g" EntrenamientoProgresivoSamadhi

Thank you in Advantage

CodePudding user response:

Assumptions:

  • :: can occur more than once on a given line of input
  • :: never shows up as data (ie, we need to replace all occurrences of ::)
  • a solution using awk is acceptable

Adding some more data to our input:

$ cat file
::Habiéndose calmado de distracciones, uno permanece completamente,
y la naturaleza superior es vista con los ojos de la sabiduría.::
some more ::text1:: and then some more ::text2:: the end

One awk idea:

awk '
BEGIN { tag[0]="<b>"; tag[1]="</b>" }
      { while (sub(/::/,tag[c%2])) c  ; print }
' file

This generates:

<b>Habiéndose calmado de distracciones, uno permanece completamente,
y la naturaleza superior es vista con los ojos de la sabiduría.</b>
some more <b>text1</b> and then some more <b>text2</b> the end

CodePudding user response:

Using GNU sed

$ sed -Ez 's~::(.[^:]*)::~<b>\1</b>~' input_file
<b>Habiéndose calmado de distracciones, uno permanece completamente, 
y la naturaleza superior es vista con los ojos de la sabiduría.</b>

CodePudding user response:

Use awk and increment a counter variable. Then you can perform a different substitution depending on whether it's odd or event.

awk '/::/ && counter   % 2 == 0 {sub("::", "<b>") }
     /::/ {sub("::", "</b>") }
     1' 

Note that this will only work correctly if the start and end :: are on different lines.

CodePudding user response:

This might work for you (GNU sed):

sed ':a;/::/{x;s/^/x/;/xx/{s///;x;s/::/<\/b>/;ba};x;s/::/<b>/;ba}' file

If a line contains ::, swap to the hold space and increment a counter by inserting an x at the start of the line.

If the counter is 2 i.e. the swap space contains xx, reset the counter and then swap back to the pattern space and replace :: by <\b> and go again (in the case that a line contains 2 or more :: strings).

Otherwise, swap back to the pattern space and replace :: by <b and go again (for reasons explained above).

All other lines are untouched.

  • Related