假设我的目录中有许多包含以下内容的*.txt
文件。texts
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Aliquam tincidunt mauris eu risus.
Vestibulum auctor dapibus neque.
我想用以下内容替换它们递归地。
Vestibulum commodo felis quis tortor.
Ut aliquam sollicitudin leo.
Cras iaculis ultricies nulla.
Donec quis dui at dolor tempor interdum.
因为这是一个相当大的替代品。逐一键入可能非常耗时。
因此,我认为如果有这样的选择会更好。
复制和粘贴将原始文本放入文件中original.txt
,并将所需的替换内容放入另一个文件中update.txt
。
然后执行命令查找*.txt
目录下所有texts
由 内容组成的文件,original.txt
并将其替换为 的内容update.txt
。
类似于简单的替换,例如:
find texts -name "*.txt" -exec sed -i 's/original/update/g' {} \;
我想这样就不会像手动打字那样出现错误,而且消耗的时间也会更少。
但我不知道应该使用什么命令来实现这一目标?这可能吗。
但是,首先我必须能够验证原文的可用性和出现的次数。
类似于简单检查,例如:
cd texts
grep -r --color=always "original" | wc -l
谢谢。
答案1
我会使用 perl 而不是 sed (或 awk):
find texts/ -name '*.txt' \
-exec perl -0777 -p -i.bak -e '
BEGIN {
$search = q{Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Aliquam tincidunt mauris eu risus.
Vestibulum auctor dapibus neque};
$replace = q{Vestibulum commodo felis quis tortor.
Ut aliquam sollicitudin leo.
Cras iaculis ultricies nulla.
Donec quis dui at dolor tempor interdum.};
};
s/\Q$search\E/$replace/mg' {} +
-0777
告诉 perl 立即“slurp”整个文件并将其作为一个长字符串处理-p
使 perl 的行为类似于sed
(并且对应-n
选项使其工作方式类似于sed -n
)。-i.bak
对文件进行“就地”编辑,保存带有.bak
扩展名的原始文件。再次,类似于sed -i
.如果您不需要备份副本,请使用 just
-i
代替-i.bak
。\Q
在 perl 正则表达式中,告诉 perl 将以下模式(直到它看到 a\E
)视为文字字符串,即使它包含正则表达式特殊字符。从
man perlre
:\Q
引用(禁用)模式元字符直到\E
\E
结束案例修改或引用部分q{}
q
使用与单引号完全相同的perl引用运算符。它在 perl 脚本已经用单引号括起来的单行代码中特别有用(其中不能用反斜杠转义因为单引号内的转义码会被忽略)。查看man perlop
并搜索“引用和类引用运算符”。另请参见perldoc -f q
(并与perldoc -f qq
双引号运算符进行比较)。
顺便说一句,我建议仅在单个文件上测试该文件的 perl 部分,并检查输出以确保它将执行我想要的操作(即没有 find ,尤其是没有-i.bak
)。
答案2
这是在 Debian 11 中完成的一种方法:
- bash v.5.1.4(1)
- tr (GNU Coreutils) v.8.32
- sed (GNU sed) v.4.7
这个脚本是这样写的
- 假设每个有问题的文件都有
.txt
扩展名 .txt
必须在-files所在的同一目录中运行- 处理时显示每个文件的名称和内容
- 创建新文件而不是就地替换,以确保原始文件在发生故障时仍然可用。此外,如果例如需要更改替换文本,则可以使用单个命令删除新创建的文件,而不影响原始文件。
目录内容:
pg1@TREX:~/foo$ ls
repla.sh text1.txt text2.txt
文本文件内容:
pg1@TREX:~/foo$ for i in {1..2}; do cat text$i.txt; echo; done
This is the beginning
of the first text.
These lines
will be replaced.
This is the ending
of the first text.
This is the beginning
of the second text.
These lines
will be replaced.
This is the ending
of the second text.
替换文本:
New lines
that will replace
old lines.
替换.sh:
#!/bin/sh
for i in *.txt; do
echo $i
cat text.txt | tr '\n' '\r' | sed -e 's/These lines\rwill be replaced./New lines\rthat will replace\rold lines./g' | tr '\r' '\n' | tee $i.new
done
结果:
pg1@TREX:~/foo$ ./repla.sh
text1.txt
This is the beginning
of the first text.
New lines
that will replace
old lines.
This is the ending
of the first text.
text2.txt
This is the beginning
of the second text.
New lines
that will replace
old lines.
This is the ending
of the second text.
pg1@TREX:~/foo$ ls
repla.sh text1.txt text1.txt.new text2.txt text2.txt.new
脚本需要根据需要进行调整,例如,如果还有具有不同扩展名(或没有扩展名)的文本文件需要修改,或者文件位于不同的目录中,则需要适应这种情况。注释掉echo $i
可以防止在处理时显示文件名,| tee
用>
重定向替换可以防止显示文件内容。就地替换需要创建新文件,只需添加mv
到脚本即可替换原始文件。
请注意下面埃德·莫顿的评论。
还有其他解决方案,很可能更优雅;并且更适合较长的段落。例如在这个堆栈溢出问题旧段落和替换段落位于变量中。