Issue
I have a file that contains the following data:
GS*PO*112233*445566*20211006*155007*2010408*X*004010~
ST*850*0001~
BEG*00*DS*A-112233**20211005~
REF*K6*Drop Ship Order~
REF*ZZ*SO168219~
REF*DC*ABC~
ST*850*0002~
BEG*00*DS*A-44556**20211005~
REF*K6*Drop Ship Order~
REF*ZZ*PO54361~
ST*850*0003~
BEG*00*DS*A-12345**20211005~
REF*K6*Drop Ship Order~
REF*DC*XYZ~
REF*ZZ*SO897654~
For clarity, I have inserted blank line above each ST*850
line. Here is what I want to do:
- Search for the pattern
REF*ZZ*SO
- If found, then replace the preceding
ST*850
line withST*850C
So the resultant file would look like this:
GS*PO*112233*445566*20211006*155007*2010408*X*004010~
ST*850C*0001~
BEG*00*DS*A-112233**20211005~
REF*K6*Drop Ship Order~
REF*ZZ*SO168219~
REF*DC*ABC~
ST*850*0002~
BEG*00*DS*A-44556**20211005~
REF*K6*Drop Ship Order~
REF*ZZ*PO54361~
ST*850C*0003~
BEG*00*DS*A-12345**20211005~
REF*K6*Drop Ship Order~
REF*DC*XYZ~
REF*ZZ*SO897654~
Here is what I have tried:
sed -i -n '/^REF\*ZZ\*SO/!{x;s/ST\*850\*/ST\*850C\*/;x};x;1!p;${x;p}' file
This replaces all the three ST*850
lines with ST*850C
and not just the 1st and the 3rd. What am I doing wrong?
Solution
How about a perl
solution although perl is not included in the tags.
perl -0777 -aF'(?=ST\*850)' -ne '
print map {/REF\*ZZ\*SO/ && s/ST\*850/$&C/; $_} @F;
' file
Output:
GS*PO*112233*445566*20211006*155007*2010408*X*004010~
ST*850C*0001~
BEG*00*DS*A-112233**20211005~
REF*K6*Drop Ship Order~
REF*ZZ*SO168219~
REF*DC*ABC~
ST*850*0002~
BEG*00*DS*A-44556**20211005~
REF*K6*Drop Ship Order~
REF*ZZ*PO54361~
ST*850C*0003~
BEG*00*DS*A-12345**20211005~
REF*K6*Drop Ship Order~
REF*DC*XYZ~
REF*ZZ*SO897654~
- The
-0777
option tellsperl
to slurp whole file at once. - The
-a
option enables theauto split
mode then the split fragments are stored in the array@F
. - The
-F
option specifies the pattern to split the input. - The regex
(?=ST\*850)
is a positive lookbehind which matches at the beginning of a stringST*850
. - The
-ne
option is mostly equivalent to that ofsed
. - The
map {..} @F
function converts all elements of@F
according to the statement within the curly brackets. - The statement
/REF\*ZZ\*SO/ && s/ST\*850/$&C/
is translated as: "if the element of @F matches the pattern /REF*ZZ*SO/, then perform the substitution s/ST*850/$&C/ for the element." - The final
$_
is the perl's default variable similar to thepattern space
of sed and will be the return values of the map function.
Answered By - tshiono