我有一个文件“changesDictionary.txt”包含(可变数量)的键值string对。
例如
“textToSearchFor”=“theReplacementText”
(字典格式不重要,可根据需要更改。)
我需要遍历给定目录的内容,包括子目录。 对于遇到扩展名为“.txt”的每个文件,我们searchchangesDictionary.txt中的每个键,用replace的string值replace每个find的实例。
即search和replace多个文件,但是使用search/replace术语列表而不是单个search/replace术语。
我怎么能这样做? (我研究过单个search/replace的例子,但不知道如何在一个文件中进行多次search。)
只要我可以从Mac OS X的命令行运行它,实现(bash,perl,whatever)并不重要。感谢您的帮助。
我会将您的changesDictionary.txt文件转换为sed脚本,与… sed:
$ sed -e 's/^"\(.*\)" = "\(.*\)"$/s\/\1\/\2\/g/' \ changesDictionary.txt > changesDictionary.sed
请注意 ,字典中的正则表达式或sed表达式的任何特殊字符都将被sed错误地解释,所以你的字典可能只有最原始的搜索和替换,或者你需要维护sed文件有效的表达。 不幸的是,sed没有简单的方法来关闭正则表达式,只使用字符串匹配,或者将搜索和替换引用为“文字”。
使用生成的sed脚本,使用find 和 xargs – 而不是找到-exec – 通过一次处理多个文件,尽可能快地将文件转换为sed脚本。
$ find somedir -type f -print0 \ | xargs -0 sed -i -f changesDictionary.sed
请注意 ,sed的-i
选项“in-place”编辑文件,因此请务必进行备份以确保安全,或使用-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”还是“BreakThat”? 订单对于sed脚本很重要。 类似地,搜索和替换可以被搜索并且被多次替换 – 将“a”改变为“b”,可以通过另一次搜索并且从“b”替换为“c”来改变。
也许你已经考虑过这两个,但是我提到,因为我已经尝试了你之前做的事情,没有想到它。 我不知道任何事情只是做一次做多个搜索和替换的正确的事情 。 所以,你需要编程来自己做正确的事情。
这是我要做的基本步骤
在它中,将“a”=“b”替换为相应的sed行:例如(使用$ 1作为文件名)
sed -e's / a / b / g'$ 1
(你可以写一个脚本来做到这一点,或者只是手工做,如果你只需要做一次,而不是太大)。
如果这些文件都在一个目录中,那么你可以这样做:
ls * .txt | xargs scriptFromStep2.sh
如果它们在子目录中,则使用find来调用所有文件上的脚本,例如
找 。 -name'* .txt'-exec scriptFromStep2.sh {} \;
这些不是确切的,做一些实验,以确保你得到它的权利 – 这只是我将使用的方法。
(但是,如果可以的话,只要使用perl,这将会简单得多)
使用这个用Perl编写的工具 – 有相当多的花里胡哨的老人,但是好的:
http://unixgods.org/~tilo/replace_string/
特征:
多年来,这个脚本已经被大量的数据使用。
#!/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