user2415146
user2415146

Reputation: 23

Using sed to replace part of the line previous to the search pattern

Really need some help with this one, trying to use sed (hope this is the best solution) to replace last comma for each block of lat longs. examples below.

Original file

;REGION 
SOLID,
LAT,LONG,
LAT,LONG,
LAT,LONG,
LAT,LONG,
;REGION 
SOLID,
LAT,LONG,
LAT,LONG,
LAT,LONG,
LAT,LONG,
LAT,LONG,
LAT,LONG,
LAT,LONG,
;REGION 
SOLID,
LAT,LONG,
LAT,LONG,
LAT,LONG,
LAT,LONG,

Resulting file

;REGION 
SOLID,
LAT,LONG,
LAT,LONG,
LAT,LONG,
LAT,LONG;
;REGION 
SOLID,
LAT,LONG,
LAT,LONG,
LAT,LONG,
LAT,LONG,
LAT,LONG,
LAT,LONG,
LAT,LONG;
;REGION 
SOLID,
LAT,LONG,
LAT,LONG,
LAT,LONG,
LAT,LONG;

Upvotes: 2

Views: 244

Answers (5)

potong
potong

Reputation: 58578

This might work for you (GNU sed):

sed '/^;/!{H;$!d};1{h;d};x;s/,$/;/' file

or looking at it another way:

sed '/,$/{H;$!d};1{h;d};x;s//;/' file

If the line doesn't begin with ; (or does end with ,) add it to the hold space (HS) and then delete it if it is not the last line. Otherwise it must begin ';' (or does not end in ,) and if it's the first line add it to the HS and delete it else swap to the HS and subsititute the last , for ;. N.B. the current line is now in the HS. For edge case of it being the last line, it is not deleted and falls through and is also acted on by subsititution command.

Upvotes: 1

Birei
Birei

Reputation: 36282

One solution that saves only each block between region lines and substitutes last comma:

sed -n '
    ## If first line, print and process next one.
    1 { p; b };
    ## While not match "region" line, save data to hold space and
    ## process next one. If last line avoid read next one because
    ## it would end the script.
    /^;REGION/! { H; $! b }; 
    ## Get data of hold space.
    x; 
    ## Remove leading newline created with "H" instruction.
    s/^\n//; 
    ## Substitute last comma.
    s/,$/;/; 
    ## Print all.
    p; 
    ## Remove to save next block of data.
    s/^.*$//
' infile

It yields:

;REGION 
SOLID,
LAT,LONG,
LAT,LONG,
LAT,LONG,
LAT,LONG;
;REGION 
SOLID,
LAT,LONG,
LAT,LONG,
LAT,LONG,
LAT,LONG,
LAT,LONG,
LAT,LONG,
LAT,LONG;
;REGION 
SOLID,
LAT,LONG,
LAT,LONG,
LAT,LONG,
LAT,LONG;

Upvotes: 2

rzymek
rzymek

Reputation: 9311

I'd use awk:

/^;/ {if(last) print gensub(/,$/,";","",last);print; next;}
{if(last) print last; last=$0}
END {print gensub(/,$/,";","",last)}

Save this to a file like fix.awk and run

awk -f fix.awk < data

Explanations:

/^;/ {...} - execute {...} code on all lines starting with ;

print gensub(/,$/,";","",last) - replace the last , with ; in the variable last (which hold the previous line)

print; - print the current line

next - go to next line (and don't execute {if(last) print last; last=$0} on this line)

Upvotes: 2

Lev Levitsky
Lev Levitsky

Reputation: 65861

A sed solution:

sed -n 'N;/\n;/s/,\n/;\n/;P;$s/.*\n\(.*\),$/\1;/p;D' file

The ugliness is from the necessity to process the last line separately. Without it the command would be

sed -n 'N;/\n;/s/,\n/;\n/;P;D' file

Upvotes: 2

Kent
Kent

Reputation: 195269

try this awk line:

awk  '!/LONG,$/{if(p~/LONG,/)sub(/,$/,";",p)}
{if(p)print p;p=$0}
END{if(p~/LONG,/)sub(/,$/,";",p);print p}' file

Upvotes: 1

Related Questions