使用sed仅替换具有文件内容的dilimiters之间的第一个文本块

时间:2015-09-21 10:13:32

标签: regex bash sed

我的任务是更换大量文件中的许可证样板文本。因为有很多我喜欢编写脚本,所以最好使用sed在单行中进行编写。

我从this similar question知道我可以使用类似的东西:

find . -type f -exec \
    sed -i -ne '/^\/\/ DOM-IGNORE-BEGIN/ {p; r /path/to/new/license.txt' \
    -e ':a; n; /^\/\/ DOM-IGNORE-END/ {p; b}; ba}; p' '{}' \;

将找到所有文件,并将^// DOM-IGNORE-BEGIN^// DOM-IGNORE-END之间的所有内容替换为替换许可证文件的内容。这一切都很好,花花公子,它就像一个魅力。

唯一的问题是,某些文件包含多个DOM-IGNORE- *块,因此新许可证也会替换这些块中的任何内容 - 远非理想。

所以我想知道如何限制替换只是在找到的第一个块上执行它并跳过其余部分。我的正则表达在这方面缺乏。

示例输入:

Blah blah
blah blah blah

// DOM-IGNORE-BEGIN
foo foo
foo foo
// DOM-IGNORE-END

blah blah
blah blah

// DOM-IGNORE-BEGIN
foo foo
foo foo foo foo
foo foo foo
// DOM-IGNORE-END

blah blah

预期产出:

Blah blah
blah blah blah

// DOM-IGNORE-BEGIN
bar bar           <- 
bar bar           <- changed
// DOM-IGNORE-END

blah blah
blah blah

// DOM-IGNORE-BEGIN
foo foo           <-
foo foo foo foo   <- Not changed
foo foo foo       <-
// DOM-IGNORE-END

blah blah

2 个答案:

答案 0 :(得分:1)

这可能适合你(GNU sed):

sed -i -e 'x;/./{x;b};x;/DOM-IGNORE-BEGIN/,/DOM-IGNORE-END/{/DOM-IGNORE-END/!d;h;rnewLicenseFile' -e 'd}' file

这使用保留空间作为标志来防止进一步处理文件。

要保持DOM-IGNORE-BEGIN/DOM-IGNORE-END代码使用:

sed -i -e 'x;/./{x;b};x;/DOM-IGNORE-BEGIN/,/DOM-IGNORE-END/{/DOM-IGNORE-BEGIN/{p;rnewLicenseFile' -e '};/DOM-IGNORE-END/!d;h}' file

答案 1 :(得分:0)

我会使用AWK代替。虽然下面的脚本比 sed 一行更大,但我认为它更容易理解和维护:

BEGIN {
    firstBlockDone = 0
    insideFirstBlock = 0
}

! firstBlockDone && /^\/\/ DOM-IGNORE-BEGIN/ {
    insideFirstBlock = 1
    print
    next
}

! firstBlockDone && /^\/\/ DOM-IGNORE-END/ {
    insideFirstBlock = 0
    firstBlockDone = 1
    print
    next
}

insideFirstBlock {
    print "bar bar"
    next
}

{
    print
}