SED Replace after certain pattern - value in brackets

Viewed 42

I have files where i need to replace all occourences of AC %blabla% with AC (%blabla%+PAR).

ROT: S 3    BL 3900   SPEED 20
    BEN: L 15   
         
ROT: S 2    BLL (DimZ/2+25) BLR (DimZ/2-29) SPEED 20                 
    BEN: L 14-0.5 A 116  AC -1
    
 ROT: S 2   BLR (DimZ/2-29) BLL (DimZ/2-20) SPEED 20                   
     CLA: L 133 A 64    AC -1 
     
ROT: S 1    BLL (DimZ/2-29) BLR (DimZ/2+25) SPEED 20        
    BEN: L 11-0.5  AC -90
    BEN: L 95   AC 1.5 

E.g.: AC -1 should be AC (-1+PAR) afterwards. AC 90 should be AC (90+PAR) afterwards.

What i've tried is:

sed "s/\( AC"."\)/\1(/"

But that doesn't even always add the "("... I get:

ROT: S 3    BL 3900   SPEED 20
    BEN: L 15   
         
ROT: S 2    BLL (DimZ/2+25) BLR (DimZ/2-29) SPEED 20                 
    BEN: L 14-0.5 A 116  AC (-1
    
 ROT: S 2   BLR (DimZ/2-29) BLL (DimZ/2-20) SPEED 20                   
     CLA: L 133 A 64    AC -1 
     
ROT: S 1    BLL (DimZ/2-29) BLR (DimZ/2+25) SPEED 20        
    BEN: L 11-0.5  AC (-90
    BEN: L 95   AC (1.5

Could someone please help me?

Thank you.

2 Answers
$ sed -E 's/(AC )([^ ]*)/\1(\2+PAR)/' ip.txt
ROT: S 3    BL 3900   SPEED 20
    BEN: L 15   
         
ROT: S 2    BLL (DimZ/2+25) BLR (DimZ/2-29) SPEED 20                 
    BEN: L 14-0.5 A 116  AC (-1+PAR)
    
 ROT: S 2   BLR (DimZ/2-29) BLL (DimZ/2-20) SPEED 20                   
     CLA: L 133 A 64    AC (-1+PAR) 
     
ROT: S 1    BLL (DimZ/2-29) BLR (DimZ/2+25) SPEED 20        
    BEN: L 11-0.5  AC (-90+PAR)
    BEN: L 95   AC (1.5+PAR) 
  • -E to enable Extended Regular Expressions
    • Use sed 's/\(AC \)\([^ ]*\)/\1(\2+PAR)/' if -E isn't supported
  • (AC ) to match and capture AC followed by space
    • use ( AC ) to avoid partial match or use \b(AC ) if word boundary is supported
  • ([^ ]*) to capture non-space characters
  • \1(\2+PAR) required output format

What's wrong with OP's attempt:

  • "s/\( AC"."\)/\1(/" will be treated as concatenation of s/\( AC followed by . followed by \)/\1(/
    • can be simplified to sed 's/\( AC.\)/\1(/' --> use single quotes unless double is required
  • \( AC.\) will match space followed by AC followed by any character only once
  • \1( will give you captured portion followed by (

You can use the following POSIX BRE compliant regex with sed:

sed "s/\( AC \)\([^[:space:]]*\)/\1(\2+PAR)/" file

See the online sed demo

If you have GNU sed, I suggest

sed -E "s/\b(AC\s+)(\S+)/\1(\2+PAR)/" file

See another demo.

Regex details

  • \( AC \) - Group 1: space, AC, space (so, no match for BAC, for example)
  • \([^[:space:]]*\) - Group 2: zero or more non-whitespace chars
  • \1(\2+PAR) - the replacement is the concatenated Group 1 value + ( + Group 2 value and +PAR).

GNU sed regex details

  • \b - a word boundary
  • (AC\s+) - Group 1: AC and one or more whitespaces
  • (\S+) - Group 2: one or more non-whitespace chars.
Related