用linux命令批量修改替换目录内所有文件中的内容


替换当前目录及子目录下所有.py文件中的代码

# 替换当前目录及子目录下所有.py文件中的代码
find . -type f -name "*.py" -exec sed -i 's/旧代码/新代码/g' {} +

各部分含义:

  1. -type f

    • 表示只查找普通文件(file)

    • 排除目录(-type d)、符号链接等其他类型的文件系统对象

  2. {}

    • 这是 find 命令的占位符,表示被找到的文件名

    • find 执行 -exec 后面的命令时,会用实际找到的文件名替换 {}

    • 例如找到 a.pyb.py{} 会被替换为这两个文件名

  3. +

    • 表示将多个找到的文件一次性传递给后面的命令(这里是 sed

    • 替代写法是 \;(分号需要转义),但 \; 会对每个文件单独执行命令,效率较低

    • + 的批处理方式更高效,相当于把多个文件名一起传给 sed

对比两种 -exec 结尾:

  • -exec command {} +:多个文件一起处理(高效)

  • -exec command {} \;:每个文件单独处理(低效)

完整解释: 这条命令的意思是:

1. 从当前目录(`.`)开始递归查找

2. 只找普通文件(`-type f`)

3. 文件名匹配 `*.py`(`-name "*.py"`)

4. 对找到的所有文件执行 `sed` 替换命令(`-exec ...`)

5. `sed -i` 表示直接修改原文件

6. `'s/旧代码/新代码/g'` 是 `sed` 的替换语法(全局替换)

示例: 假设目录中有 a.pyb.py,实际执行效果类似于:

sed -i 's/旧代码/新代码/g' a.py b.py

注意事项:

  1. -i 选项会直接修改原文件,建议先不加 -i 测试(去掉 -i 会打印结果但不修改文件)

  2. 如果文件名包含特殊字符(如空格),使用 {} + 也能正确处理

  3. macOS 的 sed需要写成 sed -i ''(多一个空参数)

要替换当前目录下所有 .md 文件中的 (./.webp) 为 (.webp)(其中 *** 代表任意字符),你需要使用 正则表达式 来匹配和替换。

命令如下:

find . -type f -name "*.md" -exec sed -i 's#(\./\(.*\)\.webp)#(\1.webp)#g' {} +

关键点解析:

  1. find . -type f -name "*.md"

    • 查找当前目录(.)及其子目录下的所有 .md 文件。
  2. sed -i 's#...#...#g'

    • -i:直接修改文件(不加 -i 可以先测试,不修改原文件)。

    • s#...#...#g:使用 # 作为分隔符(因为路径里有 /,避免冲突)。

  3. 正则表达式匹配 (./***.webp)

    • (\./\(.*\)\.webp) 分解:

      • \(.*\):匹配任意字符(*** 部分),并保存为 \1(反向引用)。

      • \./:匹配 ./. 需要转义,否则匹配任意字符)。

      • \.webp:匹配 .webp. 需要转义)。

  4. 替换为 (***.webp)

    • (\1.webp):\1 代表前面 \(.*\) 匹配到的内容(即 ***)。

示例: 假设 test.md 中有:

![img](./example.webp)
![img2](./subdir/image2.webp)

运行命令后,会变成:

![img](example.webp)
![img2](subdir/image2.webp)

注意事项:

  1. 测试命令(不修改文件):
find . -type f -name "*.md" -exec sed 's#(\./\(.*\)\.webp)#(\1.webp)#g' {} +
  • 去掉 -i,只打印替换后的结果,不会修改文件。
  1. macOS 用户
find . -type f -name "*.md" -exec sed -i '' 's#(\./\(.*\)\.webp)#(\1.webp)#g' {} +
  • macOS 的 sed 需要 -i ''(多一个空参数)。
  1. 如果路径有特殊字符(如空格、# 等),建议用 find -print0 + xargs -0:
find . -type f -name "*.md" -print0 | xargs -0 sed -i 's#(\./\(.*\)\.webp)#(\1.webp)#g'

这样就能批量移除 .md 文件中的 ./,只保留 (***.webp) 格式。

**如果你只想把 (./ 替换成 ((即仅删除 ./),而保留后面的 *.webp) 不变,可以使用更简单的 sed 命令:

find . -type f -name "*.md" -exec sed -i 's#(\./#(#g' {} +

解析:

  • s#(\./#(#g

    • (\./ → 匹配 (./( 是普通字符,\. 匹配 ./ 是普通字符)。

    • ( → 替换成 ((即仅删除 ./)。

    • g → 全局替换(一行中所有匹配都会被替换)。

示例: 假设 test.md 内容:

![img](./example.webp)
![img2](./subdir/image2.webp)

运行命令后,变成:

![img](example.webp)
![img2](subdir/image2.webp)

注意事项:

  1. 测试命令(不修改原文件):
find . -type f -name "*.md" -exec sed 's#(\./#(#g' {} +
  1. macOS 用户:
find . -type f -name "*.md" -exec sed -i '' 's#(\./#(#g' {} +

如果路径有空格或特殊字符,建议用 find -print0 | xargs -0

find . -type f -name "*.md" -print0 | xargs -0 sed -i 's#(\./#(#g'

总结:

  • 仅删除 ./sed 's#(\./#(#g'

  • 删除 ./ 并保留文件名(如原问题)→ sed 's#(\./\(.*\)\.webp)#(\1.webp)#g'

  • s#(./#(#g 使用了 # 作为分隔符,而不是常见的 /。这是为了避免和模式中的 / 字符冲突,使正则表达式更清晰

批量替换Hugo内容目录中所有Markdown文件的图片相对路径为绝对路径,可以按照以下步骤操作

使用find命令结合Shell脚本动态替换路径:

find content/archives -type f -name "*.md" -exec sh -c '
    file="$0"
    dir=$(dirname "$file")
    rel_path=$(echo "$dir" | sed "s|^content/archives/||")
    sed -i.bak "s|!\[\](\([^)]*\.web\))|!\[\](archives/$rel_path/\1)|g" "$file"
' {} \;

操作说明

  1. 遍历文件:find命令查找content/archives下所有.md文件。

  2. 提取路径:获取每个文件相对于content/archives的目录路径(如2002/subdir1/subdir2)。

  3. 替换路径:使用sed![](filename.web)替换为![](archives/提取的路径/filename.web)

注意事项

  1. 路径验证:替换后的路径形如archives/2002/subdir/.../file.web,确保该路径在站点中有效。

  2. 前导斜杠:若需绝对URL路径,将替换部分改为![](/archives/$rel_path/\1)(添加斜杠)。

  3. 备份文件:脚本会生成.bak备份文件,处理完毕后可运行find content/archives -name "*.bak" -delete清理。

  4. 扩展名适配:如需处理其他图片格式(如.png),修改正则中的.web.\(web\|png\|jpg\)

示例效果 文件content/archives/2002/a/b/post.md中的:

![](01.web)

将被替换为:

![](archives/2002/a/b/01.web)

执行前请务必备份内容目录,测试无误后再应用到全部文件。

如果![]()[]中有不同的内容而只要修改替换()中的内容可按以下方案操作:

精准替换方案(保留 Alt 文本)

find content/archives -type f -name "*.md" -exec sh -c '
    file="$0"
    dir=$(dirname "$file")
    # 提取从 archives 开始的相对路径(如 2002/subdir1/subdir2)
    rel_path=$(echo "$dir" | sed "s|^content/archives/||")
    # 精准替换括号内的路径,保留 Alt 文本
    sed -i.bak "s|(\\([^)]*\\.web\\))|(archives/$rel_path/\\1)|g" "$file"
' {} \;

关键改进点

  1. 精准匹配 (\\([^)]*\\.web\\)) 仅匹配括号内的 .web 路径,保留 ![描述] 中的 Alt 文本不变。

  2. 动态路径插入 rel_path 变量会自动提取 MD 文件所在的层级路径(如 2002/subdir1/subdir2),并插入到图片路径中。

  3. 保留原始结构 替换后的路径格式为:archives/2002/subdir1/subdir2/0.web,与你的目录结构完全一致。

操作步骤

  1. 终端执行命令 复制上述脚本到终端运行,自动处理所有 .md 文件。

  2. 验证替换结果 示例文件 content/archives/2002/a/b/post.md 中的:

![任意 Alt 文本](0.web)
![图片描述](test.web)

会被替换为:

![任意 Alt 文本](archives/2002/a/b/0.web)
![图片描述](archives/2002/a/b/test.web)
  1. 清理备份文件 确认无误后执行清理:
find content/archives -name "*.md.bak" -delete

常见问题排查

  1. 路径未生效
  • 检查 rel_path 是否正确:在脚本中添加 echo "Processing: $file → $rel_path"输出路径调试。

  • 确保 Hugo 的 static/ 目录或发布配置能正确映射 archives/ 路径。

  1. 特殊字符问题 如果路径含空格或特殊符号,在 sed 中用双引号包裹变量:"archives/$rel_path/\\1"

  2. 多格式支持 如需适配 .png.jpg,修改正则表达式为:

sed -i.bak "s|(\\([^)]*\\.\\(web\\|png\\|jpg\\)\\))|(archives/$rel_path/\\1)|g" "$file"

执行示例

# 测试单个文件(替换前预览)
sed "s|(\\(.*\.web\\))|(archives/2002/a/b/\1)|g" post.md

# 实际执行(全量替换)
find content/archives -type f -name "*.md" -exec sh -c '...' {} \;

此方案确保仅修改括号内的图片路径,完美保留 Markdown 原有结构和 Alt 描述文本。

Built with Hugo
Theme Stack designed by Jimmy