Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

268
Views
Linux bash: How do I replace a string on a line based on a pattern on another/different line?

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:

  1. Search for the pattern REF*ZZ*SO
  2. If found, then replace the preceding ST*850 line with ST*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?

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

This might work for you (GNU sed):

sed '/ST\*850/{:a;/REF\*ZZ\*SO/!{N;ba};s/.*ST\*850/&C/}' file

Begin gathering up lines if a line contains ST*850.

On matching a line that contains REF*ZZ*SO use greed to append C to the latest ST*850 string.

N.B. The regexp .* ensures that the match will backtrack from the end of the collection rather than the start of the collection.

over 4 years ago · Santiago Trujillo Report

0

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 tells perl to slurp whole file at once.
  • The -a option enables the auto 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 string ST*850.
  • The -ne option is mostly equivalent to that of sed.
  • 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 the pattern space of sed and will be the return values of the map function.
over 4 years ago · Santiago Trujillo Report

0

Assuming ST is essentially a record separator, you can use a simple Awk script to collect the lines in the current record, and print a modified different one if the conditions are right.

awk 'BEGIN { ORS = RS = "\nST" }
    /REF\*ZZ\*SO/ { sub(/^\*850/, "*<850C") }1' filename

The BEGIN clause sets the record separator (RS) and also the output record separator (ORS) to the string ST preceded by a newline. (Attempting to include the asterisk got complicated, so I avoided that.) The final 1 is the common Awk shorthand for "print everything which reaches here".

sed is rather unwieldy for anything beyond simple line-based substitutions; I think you will find that switching to a higher-level language is going to improve maintainability.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!