【问题标题】:How can I change the extension of files of a type using "find" with Bash? [duplicate]如何使用 Bash 的“查找”更改类型文件的扩展名? [复制]
【发布时间】:2017-01-18 05:14:10
【问题描述】:

用户输入他们正在寻找的文件类型;它存储在$arg1;他们想要更改的文件类型存储为$arg2。我能够找到我正在寻找的内容,但我不确定如何保持文件名相同,但只需更改类型......即,file1.txtfile1.log

find . -type f  -iname "*.$arg1" -exec mv {} \;

【问题讨论】:

  • @Kenavoz 所谓的重复只处理一个目录中的文件。我很确定在某处重复的,但我现在找不到。

标签: linux bash shell unix scripting


【解决方案1】:

find -exec bash 理念与bash 循环理念相结合,您可以使用-exec 上的+ 终止符来告诉find 将多个文件名传递给bash 命令的单个调用。将新类型作为第一个参数传递 - 它显示在 $0 中,因此可以方便地被其余命令行参数的 for 循环跳过 - 你有一个非常有效的解决方案:

find . -type f -iname "*.$arg1" -exec bash -c \
  'for arg; do mv "$arg" "${arg%.*}.$0"; done' "$arg2" {} +

或者,如果您有任一版本的 Linux rename 命令,您可以使用它。 Perl (又名prename,默认安装在 Ubuntu 和其他基于 Debian 的发行版上;也可通过 brew install rename 从 Homebrew 用于 OS X)可以这样使用:

find . -type f -iname "*.$arg1" -exec rename 's/\Q'"$arg1"'\E$/'"$arg2"'/' {} +

这看起来有点难看,但实际上它只是许多 UNIX 工具中熟悉的 s/old/new/ 替换命令。 \Q\E$arg1 周围的 $arg1 可以防止后缀中的任何奇怪字符被解释为可能匹配意外内容的正则表达式元字符; \E 之后的 $ 确保模式只匹配文件名的末尾。

在基于 Red Hat 的 Linux 发行版(Fedora、CentOS 等)上默认安装的基于模式的版本更简单:

find . -type f -iname "*.$arg1" -exec rename ".$arg1" ".$arg2" {} +

但它也更笨:如果你rename .com .exe stackoverflow.com_scanner.com,你会得到一个名为stackoverflow.exe_scanner.exe的文件。

【讨论】:

    【解决方案2】:

    我会这样做:

    find . -type f  -iname "*.$arg1" -print0 |\
        while IFS= read -r -d '' file; do
            mv -- "$file" "${file%$arg1}$arg2"
        done
    

    我接受了您的find 命令并将其输出提供给while 循环。在那个循环中,我正在做实际的重命名。这样,我将文件名作为变量,我可以使用 bash 的字符串操作操作进行操作。

    【讨论】:

    • 非常感谢您。试图学习这个 bash 的东西,这让我很兴奋。谢谢
    • FWIW,你不需要反斜杠;如果一行以管道结尾,则管道会自动在下一行继续,无需转义换行符。
    【解决方案3】:

    要启用shell parameter expansions 的全部功能,您可以在exec 操作中调用bash -c

    find . -type f -iname "*.$arg1" -exec bash -c 'echo mv "$0"  "${0%.*}.$1"' {} "$arg2" \;
    

    我们将{}"$arg2" 作为参数添加到bash -c,因此它们可以在命令中作为$0$1 访问。 ${0%.*} 删除扩展名,替换为 $arg2 扩展为的任何内容。

    事实上,该命令只打印它将执行的mv 命令;要真正重命名文件,必须删除 echo

    引用是相关的:bash -c 的参数用单引号括起来,防止$0$1 过早展开,mvarg2 的两个参数也被引用来处理文件名中带有空格。

    【讨论】:

      【解决方案4】:

      如果你有基于perlrename 命令

      示例目录:

      $ find
      .
      ./a"bn.txt
      ./t2.abc
      ./abc
      ./abc/t1.txt
      ./abc/list.txt
      ./a bc.txt
      

      示例参数:

      $ arg1='txt'
      $ arg2='log'
      

      试运行:

      $ find -type f -iname "*.$arg1" -exec rename -n "s/$arg1$/$arg2/" {} +
      rename(./a"bn.txt, ./a"bn.log)
      rename(./abc/t1.txt, ./abc/t1.log)
      rename(./abc/list.txt, ./abc/list.log)
      rename(./a bc.txt, ./a bc.log)
      

      如果没问题,删除-n 选项:

      $ find -type f -iname "*.$arg1" -exec rename "s/$arg1$/$arg2/" {} +
      $ find
      .
      ./a bc.log
      ./t2.abc
      ./abc
      ./abc/list.log
      ./abc/t1.log
      ./a"bn.log
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-11
        • 2012-07-17
        • 2013-03-27
        • 2016-06-29
        • 2014-02-17
        • 1970-01-01
        相关资源
        最近更新 更多