递归查找/替换,考虑目录深度

递归查找/替换,考虑目录深度

我很幸运地完成了基本的查找/替换:

find . -name "*.php" -exec sed -i -e "s/<?php include 'http:\/\/www/<?php include '..\//g" \{\} \;

我想知道是否有办法实现类似的结果,但考虑到当前目录的“深度”,并../在结构中的每个级别的替换字符串前面添加一个附加内容?

答案1

你可以尝试这样的事情:

find . -name '*.php' -exec sh -c \
'PREFIX=${1//[!/]/}; PREFIX=${PREFIX//\//..\/}; ...' sh {} \;

当找到的文件是 时,这将设置PREFIX为.然后,您可以使用 shell 变量将命令插入该位置。../dir/filenamesed...$PREFIX

这需要一个具有${var//find/repl}扩展功能的外壳。这不是 POSIX 指定的,但是BashPOSIX 的一些实现ash有它。如果你的没有,你就必须使用其他东西来进行前缀操作。在这种情况下,我将使用单个awk进程在其子句中执行前缀操作BEGIN,然后在文件的每一行上进行替换(而不是单独的sed进程)。

答案2

我有一个类似的任务来强制依赖于相对于站点根目录的目录深度的基本 URL。

下面发布完整的解决方案。它基于 @dubiousjim 的答案,但使用 shell 函数略有不同的方法来避免引用问题。

fixlinks() {
  # strip the first level depth as we don't need it
  BASE=${1/#\.\//}
  # leave only one slash char for each nested dir
  BASE=${BASE//[!\/]/}
  # replace each / with ../ (escaped to ..\/ to be used as sed replacement part)
  BASE=${BASE//\//..\\\/} 
  if [[ $BASE ]]; then
    # enable debug mode
    set -x
    # add <base> tag leading to site root after <head> for each nested file
    sed -E -i "s/<head>\r?$/<head><base href=\"$BASE\"\/>/g" "$1"
    # silently disable debug mode
    { set +x; } 2>/dev/null
  fi
}
# iterate over all files from the site root
find . -name '*.html' | while read file; do fixlinks "$file"; done

相关内容