JTLee
JTLee

Reputation: 99

Insert content from a file after specific pattern regex match by using sed in bash

I would like to insert multiple of lines from a text file before a particular text. I would like to use regex to select the particular text, and the text is like this:

//**insert_yannyann*//

『//**insert_yannyann*//』is in b.txt, and b.txt is just like that

...

//**insert_yannyann*//

...

a.txt is like that:

1234
5678
9101

For inserting a.txt text file before the pattern of text in b.txt , I tried this regex in ubuntu 18.04 bash command.

sed -n -i -e '\/\/**insert_yannyann*\/\/ /r a.txt' -e 1x -e '2,${x;p}' -e '${x;p}' b.txt

even I tried another regex pattern.

sed -n -i -e '//?\s*\*[(?=.*\insert_yannyann\b)]*?\*\s*//? /r a.txt' -e 1x -e '2,${x;p}' -e '${x;p}' b.txt

but sed always show wrong message to me for the wrong regex I used.

I want to make b.txt be like that:

...

1234
5678
9101
//**insert_yannyann*//

...

I am certainly check two of these regex is correct by some online regex tools, but I don't understand why sed show wrong message to me.

\/\/**insert_yannyann*\/\/

//?\s*\*[(?=.*\insert_yannyann\b)]*?\*\s*//?

I'm not sure whether regex regulation is the same in different programming languages, could somebody explain why it is not correct?

Upvotes: 1

Views: 398

Answers (1)

tshiono
tshiono

Reputation: 22012

Perl may not be your option, but it's worth a try. With Perl you can say:

perl -0777 -ne 'if ($. == 1) {$replace = $_; next} s#(?=//\*\*insert_yannyann\*//)#$replace#g; print' a.txt b.txt > b_new.txt

Then b_new.txt holds:

...

1234
5678
9101
//**insert_yannyann*//

...

Explanations:

  • -0777 option causes Perl to slurp whole files at once.
  • Perl variable $. holds the input line number which is equivalent to the input file number in this usecase. With this value we can switch the processings for a.txt and b.txt.
  • The $replace = $_ statement assigns the variable $replace to the content of a.txt.
  • The most important part will be the regex s#(?=//\*\*insert_yannyann\*//)#$replace#g. Perl regex supports a lookahead assertion with (?=pattern) notation. Thanks to this capability, we can easily insert a content just before the specified pattern.

Hope this helps.

EDIT

With AWK, you can do the similar thing:

awk 'NR==FNR {replace = replace $0 RS; next}
    {text = text $0 RS}
    END {
        print gensub(/\/\/\*\*insert_yannyann\*\/\//, replace "&", "g", text)
    }' a.txt b.txt > b_new.txt

The point is that the replacement string (the 2nd argument to gensub()) is a concatenation of replace, the content of a.txt, and & which represents the regex-matched string. Putting the variable replace prior to & causes the substitution before the matched pattern.

Upvotes: 1

Related Questions