Match a string that contains a newline using sed

后端 未结 4 1275
灰色年华
灰色年华 2020-12-11 02:39

I have a string like this one:

    #
    pap

which basically translates to a \\t#\\n\\tpap and I want to replace it with:

4条回答
  •  情书的邮戳
    2020-12-11 03:09

    A GNU sed solution that doesn't require reading the entire file at once:

    sed '/^\t#$/ {n;/^\tpap$/a\\tpython'$'\n''}' file
    
    • /^\t#$/ matches comment-only lines (matching \t# exactly), in which case (only) the entire {...} expression is executed:
      • n loads and prints the next line.
      • /^\tpap/ matches that next line against \tpap exactly.
      • in case of a match, a\\tpython will then output \n\tpython before the following line is read - note that the spliced-in newline ($'\n') is required to signal the end of the text passed to the a command (you can alternatively use multiple -e options).

    (As an aside: with BSD sed (OS X), it gets cumbersome, because

    • Control chars. such as \n and \t aren't directly supported and must be spliced in as ANSI C-quoted literals.
    • Leading whitespace is invariably stripped from the text argument to the a command, so a substitution approach must be used: s//&\'$'\n\t'python'/ replaces the pap line with itself plus the line to append:

      sed '/^'$'\t''#$/ {n; /^'$'\t''pap$/ s//&\'$'\n\t'python'/;}' file
      

    )


    An awk solution (POSIX-compliant) that also doesn't require reading the entire file at once:

    awk '{print} /^\t#$/ {f=1;next} f && /^\tpap$/ {print "\tpython"} {f=0}' file
    
    • {print}: prints every input line
    • /^\t#$/ {f=1;next}: sets flag f (for 'found') to 1 if a comment-only line (matching \t# exactly) is found and moves on to the next line.
    • f && /^\tpap$/ {print "\tpython"}: if a line is preceded by a comment line and matches \tpap exactly, outputs extra line \tpython.
    • {f=0}: resets the flag that indicates a comment-only line.

提交回复
热议问题