简体   繁体   中英

sed : Insert lines after specific pattern with newline

We want to modify a plist file such that after matching a pattern it should insert few lines using sed shell command.

plist file format is as follow:

<plist> 
   <dict>
     .
     .
     <key>abc</key>
     <dict>
        .
        .
     </dict>
     .
     .
    </dict>
</plist>

we want to insert few lines after finding the first dict tag.

If I use follow command it inserts after all dict tag in file.

sed -i '' "/<dict>/ r template" info.plist

So, I tried to find plist and dict tag and insert lines after that.

sed -i '' "/<plist version=\"1.0\">\n<dict>/r template" info.plist

or

sed -i '' "/\(^<plist version=*.\)/ r template" info.plist

This also doesn't work for this it is not able to find the pattern in file.

Please suggest me how can I put a pattern which contains two strings separated by newline.

这可能适合你(GNU sed):

sed -i -e '1,/<dict>/{/<dict>/{r template' -e '}}' file

sed is an excellent tool for simple substitutions on a single line, for anything else just use awk. If you're using anything other than s, g, and p (with -n) in sed then you are using the wrong tool and language constructs that became obsolete in the mid-1970s when awk was invented.

There's a lot of ways you could do this. Here's one:

$ cat file1
<plist>
   <dict>
     .
     .
     <key>abc</key>
     <dict>
        .
        .
     </dict>
     .
     .
    </dict>
</plist>

.

$ cat file2
now is the
winter of
our discontent

.

$ awk 'NR==FNR{extra = extra $0 RS; next} {print} /<dict>/ && ++count==1{printf "%s", extra}' file2 file1
<plist>
   <dict>
now is the
winter of
our discontent
     .
     .
     <key>abc</key>
     <dict>
        .
        .
     </dict>
     .
     .
    </dict>
</plist>

Want to print after the 2nd occurrence of dict instead of the first? Just change ==1 to ==2 :

$ awk 'NR==FNR{extra = extra $0 RS; next} {print} /<dict>/ && ++count==2{printf "%s", extra}' file2 file1
<plist>
   <dict>
     .
     .
     <key>abc</key>
     <dict>
now is the
winter of
our discontent
        .
        .
     </dict>
     .
     .
    </dict>
</plist>

Want to search for a pattern spanning multiple lines instead of the Nth occurrence of a pattern? Here's one way with GNU awk for multi-char RS and gensub():

$ awk -v RS='^$' 'NR==FNR{extra=$0;next} {print gensub(/<plist>[[:space:]]+<dict>\n/,"&"extra,"")}' file2 file1
<plist>
   <dict>
now is the
winter of
our discontent
     .
     .
     <key>abc</key>
     <dict>
        .
        .
     </dict>
     .
     .
    </dict>
</plist>

All trivial stuff with awk.

To update the original file with any UNIX command is:

command file > tmp && mv tmp file

so in this case it's:

awk 'script' file > tmp && mv tmp file

GNU awk has a -i inplace argument that works like seds -i to create the tmp file behind the scenes if you prefer the marginal brevity:

awk -i inplace 'script' file

尝试使用'N'命令启用换行符匹配:

sed 'N;/<plist>\n\s\+<dict>/a added line' info.plist

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM