0

I have input like this:

*123456789
This is a <secret>
Other stuff here.
*987654321
This is a <secret>
Other stuff here.

where "Other stuff here." could be one more lines, but the number prefixed by * is variable but will always take up the whole line, and will always appear on the line immediately before the "<secret>", which is a literal, fixed string that can be matched against.

I'd like to be able to pipe this into a one-line command in a shell script such that the "*123456789" string will substitute the <secret> that appears on the next line, so that the output would be:

This is a *123456789
Other stuff here.
This is a *987654321
Other stuff here.

I'm struggling to understand multi-line processing in sed and am open to using another tool if it's cleaner.

2 Answers 2

3

Using sed, you could pull in the next line using N and then re-arrange the parts with s. For example:

$ sed -E '/^\*[0-9]{1,}$/{N;s/(.*)\n(.*)<secret>/\2\1/}' file
This is a *123456789
Other stuff here.
This is a *987654321
Other stuff here.
1
  • Beautiful, thank you. I had the regular expression, but didn't quite have the N syntax right.
    – dlo
    Commented Sep 1, 2019 at 15:31
3
$ awk '/^\*/ {secret=$0;next}; {gsub(/<secret>/,secret,$0); print}' input.txt 
This is a *123456789
Other stuff here.
This is a *987654321
Other stuff here.

If you wanted to strip the leading * from the "secret", you could use awk's substr() function:

$ awk '/^\*/ {secret=substr($0,2);next}; {gsub(/<secret>/,secret,$0); print}' input.txt 
This is a 123456789
Other stuff here.
This is a 987654321
Other stuff here.
2
  • I confirmed that this works as well. Thank you.
    – dlo
    Commented Sep 1, 2019 at 15:32
  • +1 -- maybe subjective, but awk 's syntax tend to be remarkably more readable than sed 's in this case, even if the example was simple.
    – Cbhihe
    Commented Sep 1, 2019 at 20:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .