【问题标题】:How do I rename the extension for a bunch of files?如何重命名一堆文件的扩展名?
【发布时间】:2010-11-16 12:31:54
【问题描述】:

在一个目录中,我有一堆*.html 文件。我想将它们全部重命名为*.txt

我该怎么做?我使用 bash shell。

【问题讨论】:

    标签: bash rename file-rename


    【解决方案1】:

    如果使用 bash,则不需要 sed、basename、rename、expr 等外部命令。

    for file in *.html
    do
      mv "$file" "${file%.html}.txt"
    done
    

    【讨论】:

    • 如果您不知道文件扩展名,您可以使用"${file%.*}.txt",但这对于没有扩展名的文件可能很危险。
    • 请注意任何无法像我一样工作的人:请注意花括号内没有$
    • 我需要一种方法来永久收藏/收藏这个答案,我不记得确切的语法,我最终在谷歌上搜索它
    • @danip 百分号-括号内结构将字符从末尾剥离。还有一个括号内的哈希结构,可以将字符从开头剥离。检查它:tldp.org/LDP/abs/html/parameter-substitution.html#PSUB2
    • 另一个堆栈交换答案(我找不到!)建议这样做,但也使用 -- "operator": mv -- "$file" "${file%.html} .txt" 该运算符防止以 '-' 开头的文件名被 mv 解析为参数。
    【解决方案2】:

    如需更好的解决方案(仅使用 bash 功能,而不是外部调用),请参阅 one of the other answers


    以下内容可以满足并且不需要系统具有rename 程序(尽管您通常会在系统上拥有它):

    for file in *.html; do
        mv "$file" "$(basename "$file" .html).txt"
    done
    

    编辑: 正如 cmets 中所指出的,这不适用于包含空格且没有正确引用的文件名(现在在上面添加)。当纯粹在您自己的文件上工作时,您知道文件名中没有空格,这将起作用,但是每当您编写可能在以后重用的内容时,请不要跳过正确的引用。

    【讨论】:

    • 另一种选择,不带基本名称和带引号: mv "${file}" "${file/%.html/.txt}" (有关详细信息,请参阅 man bash,参数扩展)
    • 当然,只有文件都在当前目录中才好,因为 basename 去掉了路径名部分。只是“小心”!
    • 这个解决方案很糟糕,不仅因为它很慢,而且因为它不适用于包含空格的文件名。您应该始终在 bash 脚本中正确引用。 mv "$file" "$(basename "$file" .html)".txt 会好很多。但是,mv "$files" "${files%.html}.txt" 还是要好得多。
    • 在windows中你只需要ren *.a *.b
    • 至少使用 POSIX 指定的 $() 而不是旧的反引号语法。提高可读性,并且当您有字符需要反斜杠转义以在使用后者的命令替换中成为文字时,使语法不那么模棱两可。
    【解决方案3】:
    rename 's/\.html$/\.txt/' *.html
    

    完全按照你的意愿去做。

    【讨论】:

    • 我认为您不能像您建议的那样在 bash 中使用文字正则表达式 - 您使用的是哪个 shell?
    • 这里是 Ubuntu 上 rename 版本的手册页:unixhelp.ed.ac.uk/CGI/man-cgi?rename
    • rename 是某些系统上的命令。我有一个完成这项工作的 Perl 脚本(最初来自第一本 Camel 书籍)。还有一个同名的 GNU 程序可以完成大致相同的工作。我的 Mac 没有系统提供的“重命名”命令 - 或者它不在我的 PATH 上(比较全面)。
    • Homebrew 中有一个重命名公式。
    • 我喜欢你的回答。但实际上我只会使用rename 's/jpg/png/' *.jpg,这样更容易记住和输入。如果文件名包含jpg可能会导致错误,所以我会在输入之前先检查它。
    【解决方案4】:

    这对我在 OSX 上从 .txt 到 .txt_bak 有效

    find . -name '*.txt' -exec sh -c 'mv "$0" "${0%.txt}.txt_bak"' {} \;
    

    【讨论】:

    • 在 linux 中也可以正常工作。
    • 这不是重点,但要从 .txt 转到 .txt_bak 你只需要连接 _bak ;)
    • 这很适合递归重命名
    • 太棒了! (在Ubuntu 16.04下)我的实际用例,将所有.scss重命名为.sass(就地转换后...):find . -name '*.scss' -exec sh -c 'mv "$0" "${0%.scss}.sass"' {} \;
    • 这适用于 +6000 个文件,重命名报告“参数列表太长”
    【解决方案5】:

    你想使用rename

    rename -S <old_extension> <new_extension> <files>
    
    rename -S .html .txt *.html
    

    这正是您想要的 - 它会将所有匹配 *.html 的文件的扩展名从 .html 更改为 .txt

    注意:Greg Hewgill 正确地指出这不是内置的 bash;并且是一个单独的 Linux 命令。如果您只需要 Linux 上的某些东西,这应该可以正常工作;如果您需要更多跨平台的东西,请查看其他答案之一。

    【讨论】:

    • 虽然这是一个很好的解决方案,但rename 程序与bash 无关,也并非在所有平台上都可用。我只在 Linux 上看到过。
    • "$rename .html .txt *.html" 导致... (eval 1) 第 1 行“.”附近出现语法错误
    • 正确的语法是rename -S .html .text *.html,其中-S代表--subst-all
    • @GregHewgill 重命名可用于带有 HomeBrew 的 Mac OS
    • util-linux 的重命名 2.28.2 没有 -S 选项。不过,没有它也可以。
    【解决方案6】:

    在 Mac 上...

    1. 如果你还没有安装renamebrew install rename
    2. rename -S .html .txt *.html

    【讨论】:

      【解决方案7】:

      对于 Ubuntu 用户:

      rename 's/\.html$/\.txt/' *.html
      

      【讨论】:

      • 这不是递归的,但它在 Ubuntu 14.04 上对我有用。
      【解决方案8】:

      这是我发现的适用于 OSX 和 Linux 的最巧妙的解决方案,它也适用于 git!

      find . -name "*.js" -exec bash -c 'mv "$1" "${1%.js}".tsx' - '{}' \;

      和 git:

      find . -name "*.js" -exec bash -c 'git mv "$1" "${1%.js}".tsx' - '{}' \;

      【讨论】:

      • 不是很流畅,因为它为每个文件启动一个新的 bash。其实很慢请使用管道和 xargs。
      • 我想这是真的。我无法想象在很多情况下,您要命名如此多的文件以至于性能很重要。此方法可以在几秒钟内重命名数百个。所以是的,我想这可能不是很好的性能,但如果你不这样做,这是一个巧妙的解决方案......
      【解决方案9】:

      这个问题明确提到了 Bash,但如果你碰巧有可用的 ZSH,那就很简单了:

      zmv '(*).*' '$1.txt'
      

      如果你得到zsh: command not found: zmv,那么只需运行:

      autoload -U zmv
      

      然后再试一次。

      感谢original article 提供有关 zmv 的提示。

      【讨论】:

      • zmv '(*).html' '$1.txt' 使用原始问题中的特定文件扩展名。
      【解决方案10】:

      以下是重命名命令的示例:

      rename -n ’s/\.htm$/\.html/’ *.htm
      

      -n 表示这是一个测试运行,实际上不会更改任何文件。如果您删除 -n,它将显示将重命名的文件列表。在上述情况下,它将当前目录中的所有文件从文件扩展名 .htm 转换为 .html。

      如果上述测试运行的输出看起来不错,那么您可以运行最终版本:

      rename -v ’s/\.htm$/\.html/’ *.htm
      

      -v 是可选的,但最好包含它,因为它是您将拥有的由 rename 命令所做的更改的唯一记录,如下面的示例输出所示:

      $ rename -v 's/\.htm$/\.html/' *.htm
      3.htm renamed as 3.html
      4.htm renamed as 4.html
      5.htm renamed as 5.html
      

      中间的棘手部分是用正则表达式替换 Perl,如下所示:

      rename -v ’s/\.htm$/\.html/’ *.htm
      

      【讨论】:

        【解决方案11】:

        一行,没有循环:

        ls -1 | xargs -L 1 -I {} bash -c 'mv $1 "${1%.*}.txt"' _ {}
        

        例子:

        $ ls
        60acbc4d-3a75-4090-85ad-b7d027df8145.json  ac8453e2-0d82-4d43-b80e-205edb754700.json
        $ ls -1 | xargs -L 1 -I {} bash -c 'mv $1 "${1%.*}.txt"' _ {}
        $ ls
        60acbc4d-3a75-4090-85ad-b7d027df8145.txt  ac8453e2-0d82-4d43-b80e-205edb754700.txt
        

        【讨论】:

        • +1 用于显示不依赖于完全匹配现有扩展的 bash-only 方式。这适用于任何输入扩展,无论是 3 个字符长还是 4 个字符长或更多
        • 改进:$ ls -1 | xargs -L 1 -I {} bash -c 'mv "$1" "${1%.*}.swift"' _ {}
        【解决方案12】:

        command mmv 似乎可以非常有效地处理大量文件(每秒数万个)。例如,要将所有 .xml 文件重命名为 .html 文件,请使用:

        mmv ";*.xml" "#1#2.html"
        

        ; 将匹配路径,* 将匹配文件名,这些在替换名称中分别称为 #1#2

        基于exec 或管道的答案要么太慢,要么在大量文件上失败。

        【讨论】:

          【解决方案13】:

          试试这个

          rename .html .txt *.html 
          

          用法:

          rename [find] [replace_with] [criteria]
          

          【讨论】:

            【解决方案14】:

            在别人的网站爬网后,我最终发现了数千个缺少 .html 扩展名的文件,分布在一大片子目录树中。

            要一次性重命名它们,除了已经具有 .html 扩展名的文件(其中大多数根本没有扩展名),这对我有用:

            cd wwwroot
            find . -xtype f \! -iname *.html   -exec mv -iv "{}"  "{}.html"  \;  # batch rename files to append .html suffix IF MISSING
            

            在 OP 的情况下,我可能会稍微修改一下,只重命名 *.txt 文件,如下所示:

            find . -xtype f  -iname *.txt   -exec filename="{}"  mv -iv ${filename%.*}.{txt,html}  \; 
            

            分解(锤击时间!):

            -iname *.txt
            - 意味着只考虑已经以 .txt 结尾的文件

            mv -iv "{}.{txt,html}" - 当 find 将 {} 作为文件名传递时,${filename%.*} 提取其基本名称而不带任何扩展名以形成 mv 的参数。 bash 将 {txt,html} 重写为两个参数,因此最终命令运行为:mv -iv "filename.txt" "filename.html"

            需要修复:处理文件名中的空格

            【讨论】:

              【解决方案15】:

              这是一次修改多个扩展的好方法:

              for fname in *.{mp4,avi}
              do
                 mv -v "$fname" "${fname%.???}.mkv"
              done
              

              注意:注意扩展大小必须相同(???)

              【讨论】:

                【解决方案16】:

                聚会有点晚了。你可以用 xargs 做到这一点:

                ls *.html | xargs -I {} sh -c 'mv $1 `basename $1 .html`.txt' - {}
                

                或者如果您的所有文件都在某个文件夹中

                ls folder/*.html | xargs -I {} sh -c 'mv $1 folder/`basename $1 .html`.txt' - {}
                

                【讨论】:

                • 没有。 Don't parse ls。这个命令很荒谬:它无用地使用带有ls 的glob,而不是直接使用glob。这将与包含空格、引号和(由于缺少引号)全局字符的文件名中断。
                • 仅供参考,您的链接文章包含一个更新的注释,上面写着较新的 ​​LS '如果打印到终端,则正确地“外壳转义”文件。不过,您的观点仍然是一个很好的经验法则。
                【解决方案17】:

                重命名当前目录和子目录下所有文件的文件扩展名,没有任何其他包(仅使用shell脚本):

                1. 在当前目录下创建一个shell脚本rename.sh,代码如下:

                  #!/bin/bash
                  
                  for file in $(find . -name "*$1"); do
                    mv "$file" "${file%$1}$2"
                  done
                  
                2. ./rename.sh .old .new 运行。

                  例如。 ./rename.sh .html .txt

                【讨论】:

                  【解决方案18】:

                  很好很简单!

                  find . -iname *.html  -exec mv {} "$(basename {} .html).text"  \;
                  

                  【讨论】:

                    【解决方案19】:

                    与之前的建议类似,我就是这样做的:

                    find . -name '*OldText*' -exec sh -c 'mv "$0" "${0/OldText/NewText}"' {} \;
                    

                    我首先验证了

                    find . -name '*OldText*' -exec sh -c 'echo mv "$0" "${0/OldText/NewText}"' {} \;
                    

                    【讨论】:

                    • 我最喜欢的答案
                    【解决方案20】:

                    如果您更喜欢 PERL,这里有一个简短的 PERL 脚本(最初由 PERL 的创建者 Larry Wall 编写)可以完全满足您的需求: tips.webdesign10.com/files/rename.pl.txt.

                    对于您的示例,以下内容应该可以解决问题:

                    rename.pl 's/html/txt/' *.html
                    

                    【讨论】:

                    • 这个问题很久以前就已经被回答和接受了,你的回答似乎并没有带来比已经说过的更多的东西。
                    • +1,因为它是 Larry Wall 脚本(由 Robin Barker 修改)。最后一个可用的网址是:tips.webdesign10.com/files/rename.pl.txt
                    【解决方案21】:

                    这是我用来将 .edge 文件重命名为 .blade.php 的内容

                    for file in *.edge; do     mv "$file" "$(basename "$file" .edge).blade.php"; done
                    

                    像魅力一样工作。

                    【讨论】:

                      【解决方案22】:

                      您还可以在 Bash 中创建一个函数,将其添加到 .bashrc 或其他内容,然后在任何您想要的地方使用它。

                      change-ext() {
                          for file in *.$1; do mv "$file" "$(basename "$file" .$1).$2"; done
                      }
                      

                      用法:

                      change-ext css scss
                      

                      函数中代码来源:https://stackoverflow.com/a/1224786/6732111

                      【讨论】:

                      • 如果您收到错误“替换错误”,则“sh”命令可能不指向 bash。用 /bin/bash 替换 sh ,它应该可以工作。
                      【解决方案23】:

                      不幸的是,可移植性并非易事。你可能需要一点 expr 魔法。

                      for file in *.html; do echo mv -- "$file" "$(expr "$file" : '\(.*\)\.html').txt"; done
                      

                      一旦你对它做你想做的事情感到满意,就移除它。

                      编辑:basename 对于这种特殊情况可能更具可读性,尽管expr 通常更灵活。

                      【讨论】:

                      • 虽然这可能不是问题的最佳答案,但它适合我!我需要一种仅在字符串中重命名整个路径的方法,而不仅仅是文件名。感谢发帖!
                      【解决方案24】:

                      这是一个使用 AWK 的解决方案。确保文件存在于工作目录中。否则,cd到html文件所在目录,然后执行以下命令:

                      for i in $(ls | grep .html); do j=$(echo $i | grep -oh "^\w*." | awk '{print $1"txt"}'); mv $i $j; done
                      

                      【讨论】:

                        【解决方案25】:

                        我在我的 .bashrc 中编写了这段代码

                        alias find-ext='read -p "Path (dot for current): " p_path; read -p "Ext (unpunctured): " p_ext1; find $p_path -type f -name "*."$p_ext1'
                        alias rename-ext='read -p "Path (dot for current): " p_path; read -p "Ext (unpunctured): " p_ext1; read -p "Change by ext. (unpunctured): " p_ext2; echo -en "\nFound files:\n"; find $p_path -type f -name "*.$p_ext1"; find $p_path -type f -name "*.$p_ext1" -exec sh -c '\''mv "$1" "${1%.'\''$p_ext1'\''}.'\''$p_ext2'\''" '\'' _ {} \;; echo -en "\nChanged Files:\n"; find $p_path -type f -name "*.$p_ext2";'
                        

                        在像“/home//example-files”这样具有这种结构的文件夹中:

                        • /home//example-files:
                          • file1.txt
                          • file2.txt
                          • file3.pdf
                          • file4.csv

                        这些命令的行为如下:

                        ~$ find-text
                        Path (dot for current): example-files/
                        Ext (unpunctured): txt
                        
                        example-files/file1.txt
                        example-files/file2.txt
                        
                        
                        ~$ rename-text
                        Path (dot for current): ./example-files
                        Ext (unpunctured): txt
                        Change by ext. (unpunctured): mp3
                        
                        Found files:
                        ./example-files/file1.txt
                        ./example-files/file1.txt
                        
                        Changed Files:
                        ./example-files/file1.mp3
                        ./example-files/file1.mp3
                        ~$
                        

                        【讨论】:

                          【解决方案26】:

                          您可以使用专为批量重命名文件而设计的工具,例如renamer.

                          要重命名当前文件夹中的所有文件扩展名:

                          $ renamer --find ".html" --replace ".txt" --dry-run * 
                          

                          更多用法示例here

                          【讨论】:

                            【解决方案27】:

                            最简单的方法是使用rename.ul,它存在于大多数 Linux 发行版中

                            rename.ul -o -v [oldFileExtension] [newFileExtension] [搜索要应用的文件的表达式]

                            rename.ul -o -v .oldext .newext *.oldext
                            

                            选项:

                            -o: 不要覆盖已有的.newext

                            -v: 详细

                            -n:试运行

                            【讨论】:

                              【解决方案28】:

                              在 Linux 或 windows git bash 或 windows 的 wsl 中,尝试以下命令以更改当前目录或子目录甚至其子目录中每个文件的扩展名,只需一行代码

                              find . -depth -name "*.html" -exec sh -c 'mv "$1" "${1%.html}.txt"' _ {} \;
                              

                              【讨论】:

                                猜你喜欢
                                • 2014-05-29
                                • 2020-01-23
                                • 2018-10-17
                                • 1970-01-01
                                • 1970-01-01
                                • 2018-01-11
                                • 2018-08-06
                                • 1970-01-01
                                • 2019-07-05
                                相关资源
                                最近更新 更多