【问题标题】:Sed/Awk replace complex string containing any possible printable characterSed/Awk 替换包含任何可能的可打印字符的复杂字符串
【发布时间】:2017-04-06 13:53:52
【问题描述】:

我需要替换一个可以包含任何可打印字符的复杂字符串。这是我无法使用 sed 替换的真实示例模式。

<!-- %cmd: for F in $(find ../[09]* -maxdepth 1 -type d -printf "%P\n" ) | grep -v "^$"; do echo "<li><a href=\"$F\">$F</a></li>"; done -->

我什至使用不可打印的 sed 分隔符来避免冲突,因为原始字符串应该只由可打印字符组成:

DELIM=$(echo -en "\001");

但它不起作用。我已经尝试了很多东西,但我无法弄清楚我错过了什么。例如:

echo "BEFORE $PATTERN AFTER" | sed -e "s${DELIM}${PATTERN}${DELIM}NEWTEXT${DELIM}"

UPDATE-1:

提供的解决方案应打印容器文本的所有行,同时用新字符串替换匹配的字符串。

pattern='<!-- %cmd: for F in $(find ../[0-9]* -maxdepth 0 -type d | sed "s/^\.\.\///"); do echo "<li><a href=\"$F\">$F</a></li>"; done -->'
container='
<h2>Title</h2>
<ul>
    <!-- %cmd: for F in $(find ../[0-9]* -maxdepth 0 -type d | sed "s/^\.\.\///"); do echo "<li><a href=\"$F\">$F</a></li>"; done -->
</ul>
'

UPDATE-2:

经过几次迭代,这是@anubhava 构建的有效、最终和公认的答案:

awk -v repl="newtext" 'FNR==NR {
    a = a $0; next
} n = index($0, a) {
    $0 = substr($0, 1, n-1) repl substr($0, n+length(a))
} 1' < (printf '%s\n' "$pattern") <(printf '%s' "$container")

Code demo

【问题讨论】:

    标签: bash shell awk replace sed


    【解决方案1】:

    您可以像这样在 sed 的分隔符中使用控制字符:

    pattern='foobar'
    delim=$'\01'
    echo "before $pattern after" | sed "s${delim}${pattern}${delim}newtext${delim}"
    
    before newtext after
    

    更新:

    由于您的模式包含各种特殊的元字符,最好放弃正则表达式 (sed) 并使用 awk 使用非正则表达式替换:

    pattern='<!-- %cmd: for F in $(find ../[09]* -maxdepth 1 -type d -printf "%P\n" ) | grep -v "^$"; do echo "<li><a href=\"$F\">$F</a></li>"; done -->'
    
    awk -v repl="newtext" 'FNR==NR {
        a = a $0; next
    }
    n = index($0, a) {
        $0 = substr($0, 1, n-1) repl substr($0, n+length(a))
    } 1' <(printf "%s\n" "$pattern") <(echo "before $pattern after")
    
    before newtext after
    

    Code Demo

    【讨论】:

    • 谢谢,但是用我在问题中显示的模式替换foobar,它对我不起作用,使用 Bash 4.3 shell。
    • @joseLuís:它适用于 GNU bash 版本 4.2.8。
    • 没有问题。这太妙了。我可以使用它。我想我要开始学习 awk,从你的解决方案开始。
    • @joseLuís:试试我编辑的 awk 命令,即awk -v repl="newtext" 'FNR==NR { a = a $0; next } n = index($0, a) { $0 = substr($0, 1, n-1) repl substr($0, n+length(a)) } 1' &lt;(printf "%s\n" "$pattern") &lt;(printf "line 1\nline 2\nbefore %s after\nline 3\nline 4\n" "$pattern")
    • 好的,这太棒了!它完美地工作!一千次感谢@anubhava 对这个问题的慷慨和坚持。我更新了code demo 以显示当前状态。如果你很好奇,代码是为website static generator 设计的,我希望我正确地归因于你的工作。很快我将更新 SO 问题。并感谢所有相关人员。这是一次很棒的经历。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 2014-03-30
    • 2018-10-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多