如何使用find的结果逐个文件执行sed?

时间:2018-02-05 15:50:33

标签: regex linux sed find

我需要通过搜索模式对文件执行替换,并通过执行另一个命令来获取替换,该命令提供要替换的字符串。但是,还需要对目录中的每个文件执行此操作。以下语法不起作用,因为sed没有输入文件。

find . type f -exec sed -i "s/<pattern1>/$(sed -n 's/abcd\(pattern2\)efgh/\1/p')/g" {} \;

这个想法是外部sed的内部sed返回pattern2用作pattern1的替代品。但是我需要在目录中的每个文件上执行此操作。我无法弄清楚语法。

如果我使用find for inside sed,

find . type f -exec sed -i "s/<pattern1>/$(find . -type f -exec sed -n 's/abcd\(pattern2\)efgh/\1/p' {} \;)/g" {} \;

我以错误结束 sed:-e expression#1,char 53:unterminated's'命令。

我可以帮忙解决这个问题吗?

2 个答案:

答案 0 :(得分:3)

如果您假设每个找到的文件都包含abcd\(pattern2\)efgh匹配,并且您想从那里取出pattern2并将其用作在同一个文件中替换pattern1,就像用户未知的原始答案一样。这是重新粉刷特定自行车棚的尝试。

find . -type f -exec sh -c 'for f; do
    sed -n "s%abcd\\(pattern2\\)efgh%s/<pattern1>/\\1/g%p" "$f" |
        sed -i -f - "$f"; done' _ {} +

这里可以突出一些事情。

  • 我们在sed替换中使用不同的分隔符,因此我们可以明确地嵌套它们。
    • 如果模式中出现%/,显然请选择另一个分隔符。
  • 因为我们无法嵌套单引号,所以我在sed脚本周围使用doube引号。这意味着所有的反斜杠必须加倍,以防止它们被吃掉#34;用双引号。
  • 我们将find结果传递给简单的sh -c脚本。
    • 为了提高效率,我重构了它以遍历找到的文件,这样就可以避免为每个找到的文件生成一个新的shell进程。简单来说,没有循环,这将是find ... -exec sh -c 'sed -n "s%foo%s/moo/bar/%p" "$1" | sed -i -f - "$1"' _ {} \;
  • sed -f -说从标准输入读取脚本。这不便携。
    • 在不起作用的平台上,尝试使用/dev/stdin代替-
    • 但是,例如在MacOS上,默认的sed只是拒绝从标准输入中读取脚本。使用临时文件或其他一些解决方法。

答案 1 :(得分:2)

如果有疑问,请牺牲简洁性以便于阅读。这是一个特殊的脚本,ad-hoc.sh(在评论和聊天中讨论之后):

#!/bin/bash
file="$1"
patternInner=$(sed -n -r "s/.*class\s*(.*)\s*:\s*public.*/\1/p" "$file")
if [[  -n "$patternInner" ]]
then
    echo -e "$patternInner matching in $file" >> findsed.log 
    # sed -i "s/void\s*\(test.*\)\s*()/MWTEST($patternInner, \1)/" "$file"
    sed "s/void\s*\(test.*\)\s*()/MWTEST($patternInner, \1)/" "$file"
else
    echo patternInner empty for file $file >&2
fi

修改:来自现实生活的sed表达。测试非空patternInner。

完成某种日志记录,如果找到模式,文件名,匹配的模式。

别忘了chmod a+x ad-hoc.sh。 如果测试看起来有效,则必须使用sed -i而不是没有-i的行激活该行,以使更改不仅发生在屏幕上,而且发生在文件中。

用法:

for f in *.?pp # would work for a flat directory as well as find.
do
    ./ad-hoc.sh "$f"
done 2> forsed.err

或发现,如果你坚持:

find . -type f -name "*.?pp" -exec ./ad-hoc.sh {} ";" 2> findsed.err

当然它可以放在单引号中并用

执行
... -exec bash -c '....(ad-hoc.sh 
     code 
     here)' {} ";" 

但在这种情况下我更喜欢ad-hoc脚本。少掩盖麻烦。更好的可编辑,更好的可测试性。

根据$ patternInner的可变性,必须考虑掩蔽,但我希望它可能只是字符和数字,没有美元,星号和反斜杠。