修改使用 `find` 找到的每个文件
modify every file found with `find`
我有一个包含一堆 .svg
文件的文件夹。
我想通过以下方式修改文件夹内的每个 svg 文件:
- 将
#000000
替换为 currentColor
- 添加
class
属性,其值基于文件名(例如,对于名为 icon-super-cool.svg
的文件,我想要 class="icon-super-cool"
这是我在谷歌上搜索了几个小时后到达的地方:
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 {} +
您的尝试存在几个问题:
- 在
find
的 exec
操作中,找到的文件的名称由 {}
表示,而不是 ${name}
。
- 即使使用
{}
,class 也会以 .svg
结尾,而不是您想要的。
- 即使使用
{}
,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 附带的默认版本 find
、sed
、basename
和 bash
,前两个解决方案也应适用。对于最后一个,你绝对需要一个像样的最新版本的 GNU awk
(参见 MacPorts 或 HomeBrew)。
我有一个包含一堆 .svg
文件的文件夹。
我想通过以下方式修改文件夹内的每个 svg 文件:
- 将
#000000
替换为currentColor
- 添加
class
属性,其值基于文件名(例如,对于名为icon-super-cool.svg
的文件,我想要class="icon-super-cool"
这是我在谷歌上搜索了几个小时后到达的地方:
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 {} +
您的尝试存在几个问题:
- 在
find
的exec
操作中,找到的文件的名称由{}
表示,而不是${name}
。 - 即使使用
{}
,class 也会以.svg
结尾,而不是您想要的。 - 即使使用
{}
,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 附带的默认版本 find
、sed
、basename
和 bash
,前两个解决方案也应适用。对于最后一个,你绝对需要一个像样的最新版本的 GNU awk
(参见 MacPorts 或 HomeBrew)。