如何用sed或awk在多行正则匹配前插入文本?
Great question! Your current sed+tr approach works, but we can definitely make this more maintainable with simpler sed syntax or a clean awk implementation. Let's break down both options:
1. GNU Sed (No tr Required)
GNU sed has a handy -z flag that reads the entire file as a single stream (using null characters as separators instead of newlines), letting us directly match multi-line patterns without converting newlines. This eliminates the need for tr entirely:
# Define the text to insert insert_text='# 1x # 2x "keyx": null, ' # Target key to match target_key='key2' # Run sed with multi-line support sed -z "s/\(\(\s*#.*\n\)*\)\(\s*\"$target_key\":\)/$insert_text\1\3/" test.txt
How it works:
- The
-zflag treats newlines as regular characters, so we can match the sequence of preceding comments with(\s*#.*\n)*(any number of lines starting with optional whitespace and a#). - The regex captures those comments and the target key line, then replaces them with your insertion text, followed by the captured comments and key line.
2. Concise Awk Implementation
Awk’s line-by-line processing and variable tracking make this task extremely readable and easy to maintain. Here’s a straightforward script:
# Define the text to insert insert_text='# 1x # 2x "keyx": null, ' # Target key to match target_key='key2' awk -v insert="$insert_text" -v key="$target_key" ' # Collect all preceding comment lines /^\s*#/ { comments = comments $0 "\n" next } # When we hit the target key line /^\s*\"'"$key"'\":/ { print insert comments $0 comments = "" next } # For all other lines, print accumulated comments + current line { print comments $0 comments = "" } # Print any remaining comments at the end of the file END { print comments } ' test.txt
How it works:
- We use a
commentsvariable to accumulate any lines that start with optional whitespace and a#. - When we encounter the target key line, we first print your insertion text, then the accumulated comments, then the key line itself.
- For all other lines, we print any accumulated comments followed by the current line, then reset the
commentsvariable. - The
ENDblock ensures we don’t miss any trailing comments in the file.
Both of these approaches will produce your desired output, and they’re far easier to read, edit, and maintain than the original sed+tr method.
内容的提问来源于stack exchange,提问作者Steve Amerige

