修改使用 `find` 找到的每个文件

modify every file found with `find`

我有一个包含一堆 .svg 文件的文件夹。 我想通过以下方式修改文件夹内的每个 svg 文件:

这是我在谷歌上搜索了几个小时后到达的地方:

find ./ -name \*.svg -exec sed -i '' -e "s/#000000/currentColor/g;s/<svg/<svg class=\"icon ${name}\"/g" {} +

颜色替换部分工作正常。当涉及 class 属性时,每个图标都获得与它处理的第一个文件的 ${name} 相同的 class 属性。

任何对我做错的帮助和解释将不胜感激。

PS。在 mac 环境中工作。

您可以使用一个小脚本(例如另存为 script.sh):

#!/bin/bash
for path in "$@"; do
    sed -i "" -e "s/#3F505A/currentColor/g;s/<svg/<svg class=\"icon-$(basename -s ".svg" "${path}")\"/g" "${path}"
done

然后像这样从 find 调用它:

find . -name '*.svg' -exec ./script.sh {} +

您的尝试存在几个问题:

  1. findexec 操作中,找到的文件的名称由 {} 表示,而不是 ${name}
  2. 即使使用 {},class 也会以 .svg 结尾,而不是您想要的。
  3. 即使使用 {},class 也会包含完整的文件路径 (./foo/bar/baz.svg),而不是您想要的。

以下假设您希望 class 名称为 icon-name,其中 name 是没有 .svg 扩展名的文件的基本名称:

find . -type f -name '*.svg' -exec bash -c \
  'b=$(basename -s.svg ""); \
   sed -i "" "s/#000000/currentColor/g;s/<svg/<svg class=\"icon-$b\"/g" ""' _ {} \;

或者,按照 Charles 的建议,减少 bash 运行次数:

find . -type f -name '*.svg' -exec bash -c \
  'for f in "$@"; do b=$(basename -s.svg "$f"); \
   sed -i "" "s/#000000/currentColor/g;s/<svg/<svg class=\"icon-$b\"/g" "$f"; done' _ {} +

如果性能确实是个问题,并且您想一次处理多个文件({} + 而不是 {} \;),sed 会很困难,因为 class 替换字符串不是常量(虽然也不是不可能,但这太可怕了)。但是 GNU awk 可以做到:

find . -type f -name '*.svg' -exec awk -i inplace '\
  BEGINFILE {s=gensub(/^(.*\/)?(.*)\.svg$/,"<svg class=\"icon-\2\"",1,FILENAME)} \
  {gsub(/#000000/,"currentColor"); gsub(/<svg/,s); print}' {} +

第一个块 (BEGINFILE) 预处理每个文件名以构建 class 替换字符串,第二个块执行替换。这应该是所有速度最快的(未测试)。

即使使用 macOS 附带的默认版本 findsedbasenamebash,前两个解决方案也应适用。对于最后一个,你绝对需要一个像样的最新版本的 GNU awk(参见 MacPorts 或 HomeBrew)。