2012-09-15 44 views
1

我想要做的是:查找和替换文件多行文件内容

find some_files -name '*.html' -exec sed -i "s/`cat old`/`cat new`/g" {} \; 

包含换行符和斜线和其他特殊字符,这导致无法正确解析的sed 。

我读过关于如何逃生换行符与SED,并命令TR,命令的printf“%Q”,但我不能让这些正常工作,也许是因为我不完全了解他们的功能。另外,我不知道为了sed工作,我仍然需要逃脱哪些特殊字符。

+1

你想达到什么目的?就目前而言,对于每个html文件,如果它发现旧文件的全部内容,则将其替换为新文件的全部内容。 –

+0

你能给我们一个例子,你想要编辑什么 – ghaschel

+0

Daniel Landau是的,这正是我想要做的。问题是这些文件包含由sed解释的特殊字符(如斜杠),我想将它们转义出来。 – Neptilo

回答

1

我不确定你想要做什么,但如果旧文件包含换行符,你可能会遇到麻烦。这是因为sed通过在每一行上应用命令来工作,所以尝试将一行与表示多行的模式匹配将不起作用,除非您明确加载更多行。

我的建议是在应用substitute命令之前将整个文件加载到sed的“缓冲区”中。然后,您必须确保新旧版本能够正确转义。此外,更令人困惑的是,旧文件(模式)的转义必须与新文件(替换)不同。

让我们先将新文件转义为“new.tmp”文件。为了清楚起见,我们将创建一个名为sed脚本 “escape_new.sed”:

#!/bin/sed -f 

# Commas used as separators 
s,\\,\\\\,g 
s,$,\\,g 
s,[/&],\\&,g 
$ a/ 

然后运行它:sed -f escape_new.sed new > new.tmp

有三个命令我们使用逃脱:

  1. 应该反斜杠在前面加上另一个反斜杠
  2. 换行符应在前面加一个反斜杠(我们通过在行末加一个反斜杠来实现)。
  3. “与”符号和斜杠应该以反斜杠开头(注意替换文本处的&实际上是一个包含匹配的运算符,因此如果它与斜线匹配,则它包含斜线,并且如果符合和符号, &符号)。
  4. 在最后一行(引用“$”符号)时,我们追加(通过“a”命令)一个斜杠。这是我们稍后将使用的替代命令的结尾斜杠。我们必须把它放在这里,因为反引号会在输入结束时删除任何额外的换行符,这可能会导致问题(例如用于引用换行符的反斜线实际上引用了终止斜杠)。

现在让我们逃避旧文件。如上所述,我们将创建一个“escape_old.sed”脚本。在我们做之前,我们需要将整个文件加载到模式空间(sed的内部缓冲区),以便我们可以替换换行符。我们可以用下面的命令做到这一点:

: a 
$! { 
    N 
    b a 
} 

第一个命令创建一个名为“a”的标签。第二个命令(“{”)实际上启动了一组命令。这里的魔力就是“$!”地址前缀。只有当最后一个输入行不是输入的最后一行(“$”表示输入的最后一行,“!”表示不是)时,该前缀才会指示它运行命令。组中的第一个命令将输入​​中的下一行附加到模式空间中。如果在最后一行执行这个“N”命令,它会终止脚本,所以我们必须小心,不要在最后一行执行它。组中的第二个命令是分支命令“b”,它将“跳转”回“a”标签。魔术是“$!”地址前缀我们有在命令之前。闭幕支架关闭该组。该组以其各自的地址前缀允许我们遍历所有行,将它们连接在一起,并在最后一行之后停止,从而允许执行任何进一步的命令。然后我们有最后的脚本:

#!/bin/sed -f 

: a 
$! { 
    N 
    b a 
} 

s,\\,\\\\,g 
s,\n,\\n,g 
s,[][/^$.],\\&,g 

如上所述,我们需要转义特殊字符。在这种情况下,一个实际的换行符现在作为一个反斜杠后跟字母n转义。在最后一个命令中,有更多的字符需要以反斜杠作为前缀。请注意,要匹配一个方括号,它需要是方括号内的第一个字符,以防止sed将它解释为我们要匹配的字符列表的最后字符。因此,在方括号中按顺序列出的字符是][/^$.

再次,我们与执行:sed -f escape_new.sed old > old.tmp

现在我们可以使用这些转义在SED命令文件,但我们必须再次全部行加载到模式空间。使用与以前相同的命令,但将它们放到一行中,我们使用紧凑形式::a;$!{N;ba}:我们现在可以在最终表达式中使用它(不包含现在位于new.tmp文件中的结束斜杠字符):

find some_files -name '*.html' -exec sed -e ":a;\$!{N;ba};s/`cat old.tmp`/`cat new.tmp`g" -i {} \; 

,希望这将工作=)

请注意,我们躲过了$符号用反斜杠,否则shell会认为我们正在试图访问最后执行的异步命令的$!变量(结果)。

+0

是的,这正是我想要做的,你的回答很好解释。 :) – Neptilo

+0

现在它*几乎*的作品。我用不同的文件样本做了一些测试。它不适用于多行文件,但当我在标准输入中输入多行文本时它确实有效。 cat命令似乎在找到换行符时终止命令行。 – Neptilo

+0

您能否提供一个不能正常工作的输入组合示例?它可以帮助找到问题。谢谢=) –