1

我有一个名为“insert.txt”的文件。它可能看起来像这样(或更丑陋):

ASDFG?|??|?\/\HJKL<MNBVCXZQWERTYUIOP
zxvbnmlkjhgfdsaqwertyuiop
123"'`~4567890987654321!@#$%^&*()
@#$%^&*()+_}{":?>

我想将目标文件(target.txt)中的一个文本块替换为“STARTSTACKOVERFLOW”到“STOPSTACKOVERFLOW”。(我在这里稍微简化了这个问题,但它是一样的)。

我用来执行此操作的 bash 脚本是:

TARGETFILE=target.txt
SOURCEFILE=insert.txt
SOURCETXT="$(<$SOURCEFILE)"
DELIMTXT=$(printf "%q" "$SOURCETXT")

sed -i -e "/STARTSTACKOVERFLOW/,/STOPSTACKOVERFLOW/cSTARTSTACKOVERFLOW\n\n${DELIMTXT}\n\nSTOPSTACKOVERFLOW\n" $TARGETFILE

问题是粘贴到“target.txt”中的内容实际上是 ANSI-C 引用的:

$'ASDFG?|??|?\/\HJKL<MNBVCXZQWERTYUIOP
zxvbnmlkjhgfdsaqwertyuiop
123"'`~4567890987654321!@#$%^&*()
@#$%^&*()+_}{":?>'

注意添加的 $''。

原因是 printf "%q" 产生了这种引用风格。我想避免这种情况——尽管需要它,因为我必须逃避这个文件中的所有坏处。

使用 bash 和 sed 是否有更好的方法来完成上述操作?

4

1 回答 1

0

POSIX sed 有一个从文件中读取的“r”命令。所以:

sed -i -e '/STARTSTACKOVERFLOW/,/STOPSTACKOVERFLOW/r large.txt' target.txt

唯一的问题是文件是读取一次,还是在开始行和停止行之间每行读取一次。我怀疑它每行读取一次......并且弄清楚如何丢弃额外的行更难......但也许:

sed -i -e '/STOPSTACKOVERFLOW/r large.txt' \
       -e '/STARTSTACKOVERFLOW/,/STOPSTACKOVERFLOW/d' target.txt

简单的演示

此版本删除了开始和结束标记。

$ cat data
sdasas
adsasdas
start
more
more
end
sdasda
sdasdad
$ cat replace
replace1
replace2
replace3
$ sed -e '/^end$/r replace' -e '/start/,/end/d' data
sdasas
adsasdas
replace1
replace2
replace3
sdasda
sdasdad

保留开始和结束标记

$ cat sedfile
/^end$/{
a\
start
r replace
a\
end
}
/^start$/,/^end$/d
$ sed -f sedfile data
sdasas
adsasdas
start
replace1
replace2
replace3
end
sdasda
sdasdad
$ 

这是更复杂的 - 如果不使用脚本文件,我不会尝试这样做,但如果你愿意,你可以这样做。不过,它不是单行的。

于 2010-10-26T18:31:21.623 回答