如何转义传递给在Linux上使用exec选项查找的命令

时间:2011-01-06 00:38:25

标签: linux sed escaping find exec

让我把我的问题分解为最简单的例子。

创建包含一行文本的测试文件。

[root@myserver ] /tmp> echo "test ReplaceMe DoNotReplaceMe" > /tmp/daj.txt

我们有一个现有的find命令,我们用它来替换匹配它的所有文件中的文本(在这个例子中,我简化了这个命令只能处理一个文件,并删除了其他的东西吧一样)。

问题在于它取代了“ReplaceMe”它出现的任何地方,而不仅仅是它本身就是一个单词。

[root@myserver ] /tmp> find /tmp/daj.txt -exec sh -c 'f="{}"; sed -e 's/ReplaceMe/#DONE#/gi' "${f#.}" ' \;
test #DONE# DoNot#DONE#

我编写了一个新的sed命令,当它本身是一个单词时,只替换“ReplaceMe”,但不是当它是另一个单词的子串时。此命令的输出是正确的。

[root@myserver ] /tmp> cat /tmp/daj.txt | sed -e 's/\(\W\)\(ReplaceMe\)\(\W\)/\1#DONE#\3/gi'    
test #DONE# DoNotReplaceMe

当我尝试将更新的sed命令合并到find命令中时,它会中断。看起来我遇到了一个逃避问题,但我没有设法通过增加额外的转义来解决它。

[root@myserver ] /tmp> find /tmp/daj.txt -exec sh -c 'f="{}"; sed -e 's/\(\W\)\(ReplaceMe\)\(\W\)/\1#DONE#\3/gi' "${f#.}" ' \;
sh: -c: line 0: syntax error near unexpected token `('
sh: -c: line 0: `f="/tmp/daj.txt"; sed -e s/(W)(ReplaceMe)(W)/1#DONE#3/gi "${f#.}" '

有没有办法逃脱我的sed命令,以便我可以通过find运行它,或者我是否需要寻找替代解决方案?

更新:我们正在运行的完整find命令打印出文件名和权限,然后将sed的输出通过管道传输到md5sum。以下是运行和匹配多个文件的示例:

[root@myserver ] ~> find /tmp -regex '.*daj.*\.txt' -printf '%p %m ' -exec sh -c 'f="{}"; sed  -e 's/ReplaceMe/#DONE#/gi' "${f#.}" | md5sum' \;
/tmp/daj2.txt 644 d52bbd311552234b761bcae694c2055a  -
/tmp/daj.txt 644 d52bbd311552234b761bcae694c2055a  -

2 个答案:

答案 0 :(得分:2)

您不应该直接在shell中使用{},而应该将文件名作为shell参数传递。另外,如果您想限制为全字匹配,请使用\<word\>作为sed

更新

find /tmp -regex '.*daj.*\.txt' -printf '%p %m ' -exec sh -c "sed  -e 's/\<ReplaceMe\>/#DONE#/gi' \$@ | md5sum" _ {} \;

输出

$ find . -regex '.*daj.*\.txt' -printf '%p %m ' -exec sh -c "sed  -e 's/\<ReplaceMe\>/#DONE#/gi' \$@ | md5sum" _ {} \;
./daj2.txt 664 ea324b4721ed037dbc2402ded4446005  -
./daj.txt 664 0bbb9104da99c1c1187a2a35e6ac0e9b  -

答案 1 :(得分:1)

这不能解答有关转义序列的问题,但可以解决问题。我基本上使用xargssed这样:

$ find ~/tmp/data.txt | xargs sed -e 's/\<replaceme\>/1234/'
1234 in this sentance
donotreplaceme in this sentance
$ 

和data.txt的内容:

replaceme in this sentance
donotreplaceme in this sentance

此外,如果您使用-print0参数可能包含空格的文件名,则告诉find将文件列表输出为空终止字符串。否则,find会将文件名中的空格解释为文件名的结尾。然后在使用xargs时,您需要使用-0参数告诉xargs输入是一个空终止字符串列表。示例如下:

find /somedir -print0 | xargs -0 command