文件内容、文件名、目录名中的“深度替换”的 Bash 函数,允许空格

文件内容、文件名、目录名中的“深度替换”的 Bash 函数,允许空格

在我的 Ubuntu 系统上,我通常需要对文件内容、文件名和目录名进行“深度替换”。例如,将源代码复制为另一个应用程序的模板时。

我已经组合了一个函数,~/.bashrc该函数可以工作,但如果查找或替换字符串中有空格,则该函数会失败。我相信这是由于sed命令不接受脚本中的空格,并且光盘如果路径包含空格,则对路径变量的修改也会失败。

参数是 ($1) 目录、($2) 查找文本、($3) 替换文本。

是否可以改进此脚本,使参数都可以包含空格?

deepreplace() {


    if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]
    then
        echo "A parameter is missing"
    else

        cd $1

        vfind=$2
        vreplace=$3 

        # Replace the string in file

        find . -type f -exec sed -i "s/$vfind/$vreplace/g" {} +

        # Replace the string in file names, then directories


        find . -type d -name "*$vfind*" | while read f; do mv $f $(echo $f | sed "s/$vfind/$vreplace/g"); done
        find . -type f -name "*$vfind*" | while read f; do mv $f $(echo $f | sed "s/$vfind/$vreplace/g"); done
    fi
}

答案1

正如评论中所述,我确定纯 bash 解决方案对于我的用例来说并不是最佳的。

我已经选择了一个依赖于 Node.js / npm 的命令(因为 Node 在我工作的环境中相当普遍,包括非 Unix(Windows / Mac))。

依赖两个npm包重命名器代替

使用这些库的优点是它们支持正则表达式和其他更高级的重命名/替换方案。

安装 Node.js / npm 后:

# Globally install the required packages (this prevents npx from trying to install in current directory if they do not already exist)

$ npm install -g renamer
$ npm install -g replace

# Set variables (dir, find, replace) for directory, find and replace strings, then run change directory, rename and replace, before reverting to original directory.
# npx is not strictly required, but have included to prevent collisions with command names on the PATH.

$ dir="./example_dir" && 
   find="example_find" && 
     replace="example_replace" && 
       cd "$dir" && 
        npx renamer --find "$find" --replace "$replace" "**" && 
            npx replace "$find" "$replace" . -r 
                && cd -

等效的 .bashrc 函数如下所示

renamereplace() {

    # Install global packages if not installed

    npm list -g renamer || npm install -g renamer
    npm list -g replace || npm install -g replace

    # Alias positional arguments

    dir="$1"
    find="$2"
    replace="$3" 

    # Change to replace directory

    cd "$dir"

    # Rename in directory and file names

    npx renamer --find "$find" --replace "$replace" "**" 

    # Replace in file contents

    npx replace "$find" "$replace" . -r 

    # Revert current directory

    cd -
}

并可以通过以下方式调用:

$ renamereplace "./example_dir" "example_find" "example_replace"

免责声明:为避免数据丢失,请确保您 a) 理解此脚本,b) 已检查此命令将在其中运行的目录,以及 c) 在运行上述命令之前已备份所有重要数据。

答案2

您的函数几乎符合您的要求,只是缺少围绕变量和替换的大量引号,这就是它不抵抗文件名中的空格的原因。

  • 变量:“$1”“$2”“$f”等
  • 替换:“$(...)”

这是第一个低接触评论:

deepreplace() {
  if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]
  then
      echo "A parameter is missing"
  else
    cd "$1" # quote missing
    vfind="$2" # quote missing
    vreplace="$3" # quote missing
    # Replace the string in file contents
    find . -type f -exec sed -i "s/$vfind/$vreplace/g" {} +
    # Replace the string in directory names
    find . -type d -name "*$vfind*" |
    while read d ; do
      mv "$d" "$(echo "$d" | sed "s/$vfind/$vreplace/g")"
    done
    # Replace the string in file names
    find . -type f -name "*$vfind*" |
    while read f; do
      mv "$f" "$(echo "$f" | sed "s/$vfind/$vreplace/g")"
    done
  fi
}

下一步改进:

  • 而不是$(echo $v | sed s/x/y/g)使用内置示例${v//x/y}
    : mv "$f" "${f//$vfind/$vreplace}"
  • 当要在目录级别以上替换路径时,您会遇到问题;这就是为什么您首先定位目录然后定位文件(而不是定位文件然后定位目录)
  • find执行三遍也没用

这是一个纯粹的 bash 新方法:

    find . | while read p ; do
      ddir="$(dirname "${p//$vfind/$vreplace}")"
      obas="$(basename "$p")"
      nbas="${obas//$vfind/$vreplace}"
      # if object rename
      [[ $obas != $nbas ]] && mv "$ddir/$obas" "$ddir/$nbas"
      # if object is file, edit
      [ -f "$ddir/$nbas" ] && sed -i "s/$vfind/$vreplace/g" "$ddir/$nbas"
    done
  • find自然输出顺序使目录始终在其子目录之前重命名,因此仅重命名基本名称元素是安全的
  • 所有名称都可以安全地包含空格
  • 只有一个人find以较低的成本完成这项工作
  • 您将依赖项保存到js

相关内容