我有一个文件,其中包含以下格式的正则表达式和替换文字字符串的列表:
OLD_REGEXP_1 NEW_STRING_1
OLD_REGEXP_2 NEW_STRING_2
...
我想用多个文件OLD_REGEXP_X
中的NEW_STRING_X
替换所有与*.txt
匹配的字符串。
我相信这是一个常见的问题,有人以前应该已经做过类似的事情,但我只是找不到使用bash编写的现有解决方案。
例如:
Tom Thompson
Billy Bill&Ted
goog1e\.com google.com
https?://www\.google\.com https://google.com
输入:
Tom and Billy are visiting http://www.goog1e.com
预期输出:
Thompson and Bill&Ted are visiting https://google.com
主要挑战是:
/
,某些工具通常将其用作正则表达式定界符视为文字。&
和\1
之类的字符,这些字符通常用作替换字符串中的反向引用元字符,但在这种情况下必须为文字。答案 0 :(得分:1)
您可以将替换列表文件转换为sed
脚本文件,然后让sed
为您完成这项工作。
尝试使用gnu sed:
sed -i -f <(sed -r 's/^(\S*) (.*)/s@\1@\2@/g' listfile) *.txt
答案 1 :(得分:1)
考虑到您到目前为止告诉我们的内容,并考虑了评论中所说的所有内容以及问题中涉及的内容以及我可能想到的所有可能的字符串,这些字符串目前并未包含在您的示例中,但是可能会出现(字符串除外)包含空格-您必须告诉我们如何在mapfile中识别旧的还是新的),听起来这就是您所需要的:
$ cat mapfile
Tom Thompson
Billy Bill&Ted
goog1e\.com google.com
https?://www\.google\.com https://google.com
$ cat textfile
Tom and Billy are visiting http://www.goog1e.com
awk '
NR==FNR {
old[NR] = $1
gsub(/&/,RS,$2)
new[NR] = $2
next
}
{
for (i=1; i in old; i++) {
gsub(old[i],new[i])
}
gsub(RS,"\\&")
print
}
' mapfile textfile
Thompson and Bill&Ted are visiting https://google.com
以上内容将“旧字符串”视为正则表达式,将“新字符串”视为不带反向引用的文字字符串,并严格按照输入文件中定义的顺序应用替换。
第一个gsub()将替换字符串中的每个&
转换为一个记录分隔符(由于我们在一条记录内进行操作,因此无法显示),因此第二个gsub()将不处理{{1 }}中的新字符串(例如反向引用),然后第三个gsub()会将RS放回&
。
以上内容可在任何UNIX系统上的任何Shell中使用任何awk进行工作。