bash 使用 sed 匹配包含换行符的字符串

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23850789/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 10:31:41  来源:igfitidea点击:

Match a string that contains a newline using sed

linuxbashubuntuawksed

提问by Romeo Mihalcea

I have a string like this one:

我有一个这样的字符串:

    #
    pap

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

这基本上转化为 a \t#\n\tpap,我想用以下内容替换它:

    #
    pap
    python

which translates to \t#\n\tpap\n\tpython.

这转化为\t#\n\tpap\n\tpython.

Tried this with sedin a lot of ways but it's not working maybe because seduses new lines in a different way. I tried with:

尝试sed了很多方法,但它不起作用可能是因为sed以不同的方式使用新行。我试过:

sed -i "s/\t#\n\tpap/\t#\tpython\n\tpap/" /etc/freeradius/sites-available/default

...and many different other ways with no result. Any idea how can I do my replace in this situation?

...以及许多不同的其他方式,但没有结果。知道在这种情况下我该如何更换吗?

采纳答案by Kent

try this line with gawk:

用 gawk 试试这一行:

awk -v RS="
sed ':a;N;$!ba;s/\t#\n\tpap/NewString/g' file
" -v ORS="" '{gsub(/\t#\n\tpap/,"yourNEwString")}7' file

if you want to let sedhandle new lines, you have to read the whole file first:

如果你想让sed处理新行,你必须先阅读整个文件:

sed '/^\t#$/{n;/^\tpap$/{p;s//\tpython/}}' file

回答by potong

This might work for you (GNU sed):

这可能对你有用(GNU sed):

sed '/^\t#$/ {n;/^\tpap$/a\tpython'$'\n''}' file

If a line contains only \t#print it, then if the next line contains only \tpapprint it too, then replace that line with \tpythonand print that.

如果一行只包含\t#打印它,那么如果下一行也只包含\tpap打印它,则将该行替换为\tpython并打印。

回答by mklement0

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

一个GNUsed的解决方案,不需要读取整个文件一次

sed '/^'$'\t''#$/ {n; /^'$'\t''pap$/ s//&\'$'\n\t'python'/;}' file
  • /^\t#$/matches comment-only lines (matching \t#exactly), in which case (only) the entire {...}expression is executed:
    • nloads and prints the nextline.
    • /^\tpap/matches that next line against \tpapexactly.
    • in case of a match, a\\tpythonwill then output \n\tpythonbefore the followingline is read - note that the spliced-in newline ($'\n') is required to signal the end of the text passed to the acommand (you can alternatively use multiple -eoptions).
  • /^\t#$/匹配仅注释行(\t#完全匹配),在这种情况下(仅)执行整个{...}表达式:
    • n加载并打印下一行。
    • /^\tpap/与下一行\tpap完全匹配。
    • 如果匹配,a\\tpython\n\tpython在读取下一行之前输出- 请注意,需要拼接换行符 ( $'\n') 来表示传递给a命令的文本的结尾(您也可以使用多个-e选项)。

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

(顺便说一句:对于BSD sed(OS X),它变得很麻烦,因为

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

    sed '/^'$'\t''#$/ {n; /^'$'\t''pap$/ s//&\'$'\n\t'python'/;}' file
    
  • 控制字符。例如\n\t不受直接支持,必须拼接为 ANSI C 引用的文字。
  • 前导空格总是从a命令的文本参数中去除,因此必须使用s//&\'$'\n\t'python'/替换方法:将pap行替换为自身加上要附加的行:

    awk '{print} /^\t#$/ {f=1;next} f && /^\tpap$/ {print "\tpython"} {f=0}' file
    

)

)



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

也不需要一次读取整个文件awk解决方案(符合 POSIX 标准):

in=$'\t#\n\tpap\n' # input string

echo "${in/$'\t#\n\tpap\n'/$'\t#\n\tpap\n\tpython\n'}"
  • {print}: prints every input line
  • /^\t#$/ {f=1;next}: sets flag f(for 'found') to 1if 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 \tpapexactly, outputs extra line \tpython.
  • {f=0}: resets the flag that indicates a comment-only line.
  • {print}: 打印每个输入行
  • /^\t#$/ {f=1;next}:如果f找到1仅注释行(\t#完全匹配)并移至下一行,则设置标志(用于 'found')。
  • f && /^\tpap$/ {print "\tpython"}: 如果一行前面是注释行并且\tpap完全匹配,则输出额外的 line \tpython
  • {f=0}: 重置指示仅注释行的标志。

回答by mklement0

A couple of pure bashsolutions:

几个纯粹的bash解决方案:

Concise, but somewhat fragile, using parameter expansion:

简洁,但有点脆弱,使用参数扩展:

in=$'\t#\n\tpap' # input string 

# Search string and string to append after.
search=$'\t#\n\tpap'
append=$'\n\tpython'

out=$in # Initialize output string to input string.
if [[ $in =~ ^(.*$'\n')?("$search")($'\n'.*)?$ ]]; then # perform regex matching
    out=${out/$search/$search$append} # replace match with match + appendage
fi

echo "$out"
  • Parameter expansion only supports patterns(wildcard expressions) as search strings, which limits the matching abilities:
  • Here the assumption is made that papis followed by \n, whereas no assumption is made about what precedes \t#, potentially resulting in false positives.
  • If the assumption could be made that \t#\n\tpapis always enclosedin \n, echo "${in/$'\n\t#\n\tpap\n'/$'\n\t#\n\tpap\n\tpython\n'}"would work robustly; otherwise, see below.
  • 参数扩展仅支持模式(通配符表达式)作为搜索字符串,这限制了匹配能力:
  • 这里的假设是在pap之后进行\n,而没有对 之前的内容进行假设\t#,这可能会导致误报。
  • 如果假设可以作出\t#\n\tpap总是封闭\necho "${in/$'\n\t#\n\tpap\n'/$'\n\t#\n\tpap\n\tpython\n'}"将有力的工作; 否则,请参见下文。

Robust, but verbose, using the =~operator for regex matching:

健壮但冗长,使用=~运算符进行正则表达式匹配:

The =~operator supports extended regular expressionson the right-hand side and thus allows more flexible and robust matching:

所述=~操作者支撑件延伸的正则表达式的右手侧,并因此允许更灵活和强大的匹配:

##代码##