我有一个包含(可变数量)键值字符串对的文件“changesDictionary.txt”。
e.g。
“textToSearchFor”=“theReplacementText”
(字典的格式不重要,可根据需要进行更改。)
我需要遍历给定目录的内容,包括子目录。对于扩展名为“.txt”的每个文件,我们在changesDictionary.txt中搜索每个键,用替换字符串值替换每个找到的实例。
即。搜索和替换多个文件,但使用搜索/替换术语列表而不是单个搜索/替换术语。
我怎么能这样做? (我研究了单个搜索/替换示例,但不了解如何在文件中进行多次搜索。)
实现(bash,perl,无论如何)只要我可以在Mac OS X中从命令行运行它就不重要了。感谢您的帮助。
答案 0 :(得分:6)
我将您的changesDictionary.txt文件转换为sed脚本,并使用... sed:
$ sed -e 's/^"\(.*\)" = "\(.*\)"$/s\/\1\/\2\/g/' \
changesDictionary.txt > changesDictionary.sed
注意,字典中的正则表达式或sed表达式的任何特殊字符都将被sed错误地解释,因此您的字典可能只有最原始的搜索和替换,或者你需要使用有效的表达式来维护sed文件。不幸的是,在sed中没有简单的方法来关闭正则表达式并仅使用字符串匹配或引用您的搜索和替换作为“文字”。
使用生成的sed脚本,使用find 和 xargs - 而不是find -exec - 来尽可能快地使用sed脚本转换文件,方法是在时间。
$ find somedir -type f -print0 \
| xargs -0 sed -i -f changesDictionary.sed
注意,sed编辑文件的-i
选项“就地”,因此请务必进行安全备份,或使用-i~
创建代字段备份
最终说明,使用搜索和替换可能会产生意想不到的后果。您是否会搜索其他搜索的子字符串?这是一个例子。
$ cat changesDictionary.txt
"fix" = "broken"
"fixThat" = "Fixed"
$ sed -e 's/^"\(.*\)" = "\(.*\)"$/s\/\1\/\2\/g/' changesDictionary.txt \
| tee changesDictionary.sed
s/fix/broken/g
s/fixThat/Fixed/g
$ mkdir subdir
$ echo fixThat > subdir/target.txt
$ find subdir -type f -name '*.txt' -print0 \
| xargs -0 sed -i -f changesDictionary.sed
$ cat subdir/target.txt
brokenThat
“fixThat”应该变成“Fixed”还是“brokenThat”?订单对sed脚本很重要。同样,搜索和替换可以多次搜索和替换 - 将“a”更改为“b”,可以通过另一次搜索和替换从“b”更改为“c”。
也许你已经考虑了这两个,但我提到因为我已经尝试过你以前做过的事并没有想到它。我不知道任何只是做正确的事情一次进行多次搜索和替换。所以,你需要对它进行编程以便自己做正确的事。
答案 1 :(得分:5)
以下是我要做的基本步骤
在其中将“a”=“b”替换为等效的sed行:例如(使用$ 1作为文件名)
sed -e's / a / b / g'$ 1
(您可以编写一个脚本来执行此操作,或者只需手动执行,如果您只需要执行此操作并且它不是太大)。
如果文件都在一个目录中,那么您可以执行以下操作:
ls * .txt | xargs scriptFromStep2.sh
如果它们在子目录中,请使用find在所有文件上调用该脚本,例如
找到。 -name'* .txt'-exec scriptFromStep2.sh {} \;这些并不准确,做一些实验以确保你做对了 - 这只是我会用的方法。
(但是,如果可以的话,只需使用perl,它就会简单得多)
答案 2 :(得分:2)
使用这个用Perl编写的工具 - 有很多花里胡哨的东西 - 老人,但是好的:
http://unixgods.org/~tilo/replace_string/
特点:
多年来,这个脚本已广泛用于大型数据集。
答案 3 :(得分:1)
#!/bin/bash
f="changesDictionary.tx"
find /path -type f -name "*.txt" | while read FILE
do
awk 'BEGIN{ FS="=" }
FNR==NR{ s[$1]=$2; next }
{
for(i in s){
if( $0 ~ i ){ gsub(i,s[i]) }
}
print $0
}' $f $FILE > temp
mv temp $FILE
done