Shell脚本 – 使用string列表在多个文件中search和replace文本

我有一个文件“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”来改变。

也许你已经考虑过这两个,但是我提到,因为我已经尝试了你之前做的事情,没有想到它。 我不知道任何事情只是做一次做多个搜索和替换的正确的事情 。 所以,你需要编程来自己做正确的事情。

这是我要做的基本步骤

  1. 复制changesDictionary.txt文件
  2. 在它中,将“a”=“b”替换为相应的sed行:例如(使用$ 1作为文件名)

    sed -e's / a / b / g'$ 1

    (你可以写一个脚本来做到这一点,或者只是手工做,如果你只需要做一次,而不是太大)。

  3. 如果这些文件都在一个目录中,那么你可以这样做:

    ls * .txt | xargs scriptFromStep2.sh

  4. 如果它们在子目录中,则使用find来调用所有文件上的脚本,例如

    找 。 -name'* .txt'-exec scriptFromStep2.sh {} \;

这些不是确切的,做一些实验,以确保你得到它的权利 – 这只是我将使用的方法。

(但是,如果可以的话,只要使用perl,这将会简单得多)

使用这个用Perl编写的工具 – 有相当多的花里胡哨的老人,但是好的:

http://unixgods.org/~tilo/replace_string/

特征:

  • 做多个搜索替换或查询替换操作
  • 搜索替换表达式可以在命令行上给出,也可以从文件中读取
  • 处理多个输入文件
  • 递归下降到目录并对所有文件执行多个搜索/替换操作
  • 用户定义的perl表达式应用于每个输入文件的每一行
  • 可选择以段落模式运行(用于多行搜索/替换)
  • 交互模式
  • 批处理模式
  • 可选备份文件和备份编号
  • 以root身份运行时保留模式/所有者
  • 忽略符号链接,空文件,写保护文件,套接字,命名管道和目录名称
  • 可选地替换只匹配/不匹配给定正则表达式的行

多年来,这个脚本已经被大量的数据使用。

 #!/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