将所有文件扩展名转换为小写

我试图低估所有的扩展,不pipe它是什么。 到目前为止,从我看到的,你必须指定要转换为小写的文件扩展名。 不过,我只是想在一个点后面把所有的东西都放低. 在名字里。

我怎样才能在bash做到这一点?

Solutions Collecting From Web of "将所有文件扩展名转换为小写"

你可以在一行中解决这个任务:

 find . -name '*.*' -exec sh -c ' a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/"); [ "$a" != "$0" ] && mv "$0" "$a" ' {} \; 

注意:这将打破包含换行符的文件名。 但现在忍受我。

使用示例

 $ mkdir C; touch 1.TXT a.TXT B.TXT C/D.TXT $ find . . ./C ./C/D.TXT ./1.TXT ./a.TXT ./B.TXT $ find . -name '*.*' -exec sh -c 'a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/"); [ "$a" != "$0" ] && mv "$0" "$a" ' {} \; $ find . . ./C ./C/D.txt ./a.txt ./B.txt ./1.txt 

说明

您可以查找当前目录( . )中有周期的所有文件. 在其名称( -name '*.*' )中,并为每个文件运行命令:

 a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/"); [ "$a" != "$0" ] && mv "{}" "$a" 

该命令的意思是:尝试将文件扩展名转换为小写(这使得sed ):

 $ echo 1.txt | sed -r "s/([^.]*)\$/\L\1/" 1.txt $ echo 2.TXT | sed -r "s/([^.]*)\$/\L\1/" 2.txt 

并将结果保存到a变量。

如果更改了某些内容[ "$a" != "$0" ] ,请重命名文件mv "$0" "$a"

正在处理的文件( {} )的名称作为其附加参数传递给sh -c ,并在命令行中显示为$0 。 它使脚本安全,因为在这种情况下,shell将数据作为数据,而不是作为代码部分,直接在命令行中指定。 ( 我感谢 @gniourf_gniourf 指出我这个非常重要的问题 )。

如您所见,如果直接在脚本中使用{} ,则可能会在文件名中进行一些shell注入,如下所示:

 ; rm -rf * ; 

在这种情况下,注入将被shell视为代码的一部分,并被执行。

虽然版本

更清楚,但更长的脚本版本:

 find . -name '*.*' | while IFS= read -rf do a=$(echo "$f" | sed -r "s/([^.]*)\$/\L\1/"); [ "$a" != "$f" ] && mv "$f" "$a" done 

这仍然打破了包含换行符的文件名。 要解决这个问题,你需要find一个支持-print0 (比如GNU find )和Bash(这样read支持-d分隔符开关):

 find . -name '*.*' -print0 | while IFS= read -r -d '' f do a=$(echo "$f" | sed -r "s/([^.]*)\$/\L\1/"); [ "$a" != "$f" ] && mv "$f" "$a" done 

如果你真的想要一个简单的方法(你应该!),用最近版本的Bash(Bash≥ 4.0)支持,,参数扩展这里是最终的解决方案:

 find . -name '*.*' -print0 | while IFS= read -r -d '' f do base=${f%.*} ext=${f##*.} a=$base.${ext,,} [ "$a" != "$f" ] && mv -- "$f" "$a" done 

回到原来的解决方案

或者在一个find去(回到原来的解决方案,一些修复,使它真的很简单):

 find . -name '*.*' -type f -exec bash -c 'base=${0%.*} ext=${0##*.} a=$base.${ext,,}; [ "$a" != "$0" ] && mv -- "$0" "$a"' {} \; 

我添加了-type f以便只有常规的文件被重命名。 如果没有这个,如果目录名称在文件名之前被重命名,你仍然可能会遇到问题。 如果你还想重命名目录(和链接,管道等),你应该使用-depth

 find . -depth -name '*.*' -type f -exec bash -c 'base=${0%.*} ext=${0##*.} a=$base.${ext,,}; [ "$a" != "$0" ] && mv -- "$0" "$a"' {} \; 

以便find执行深度优先搜索。

你可能会争辩说,为每个找到的文件产生一个bash进程是没有效率的。 这是正确的,以前的循环版本会更好。

我得到了这个命令的成功。

 rename JPG jpg *.JPG 

其中rename是一个命令,告诉外壳重新命名JPG文件到当前文件夹中的所有JPG文件名。

如果您看到Bareword“JPG”不允许,而在(eval 1)第1行使用“strict subs”,则使用此方法尝试:

 rename 's/\.JPG$/.jpg/' *.JPG 

那么,你可以使用这个片段作为你需要的任何替代方案的核心:

 #!/bin/bash # lowerext.sh while read f; do if [[ "$f" = *.* ]]; then # Extract the basename b="${f%.*}" # Extract the extension x="${f##*.}" # Convert the extension to lower case # Note: this only works in recent versions of Bash l="${x,,}" if [[ "$x" != "$l" ]]; then mv "$f" "$b.$l" fi else continue fi done 

之后,您只需要将需要重命名的文件列表输入到其标准输入中即可。 例如,对于当前目录和任何子目录下的所有文件:

 find -type f | lowerext.sh 

一个小优化:

 find -type f -name '*.*' | lowerext.sh 

如果您需要比这更具体的答案,您将不得不更具体…

这是更短,但更一般,结合他人的答案:

 rename 's/\.([^.]+)$/.\L$1/' * 

模拟

对于模拟,请使用-n ,即rename -n 's/\.([^.]+)$/.\L$1/' * 。 通过这种方式,您可以看到在执行实际更改之前会发生什么变化。 示例输出:

 Happy.Family.GATHERING.JPG renamed as Happy.Family.GATHERING.jpg Hero_from_The_Land_Across_the_River.JPG renamed as Hero_from_The_Land_Across_the_River.jpg rAnD0m.jPg1 renamed as rAnD0m.jpg1 

有关语法的简短说明

  • 语法被rename OPTIONS 's/WHAT_TO_FIND_IN_THE_NAME/THE_REPLACEMENT/' FILENAMES
  • \.([^.]+)$表示字符串( $ )末尾的点( [^.] ),点( \.
  • .\L$1表示点( \. ),后跟小写( \L )的第一组( $1
  • 在这种情况下,第一组是扩展名( [^.]+
  • 您最好使用单引号而不是双引号来包装正则表达式以避免shell扩展

这将为你的.mp3的工作 – 但只在工作目录中 – 但是能够消耗空白的文件名:

 for f in *.[mM][pP]3; do mv "$f" "${f%.*}.mp3"; done 

更正:

 for f in *.[mM][pP]3; do [[ "$f" =~ \.mp3$ ]] || mv "$f" "${f%.*}.mp3"; done 

如果您安装了mmv (=移动多个文件),并且您的文件名至多包含一个点,则可以使用

 mmv -v "*.*" "#1.#l2" 

它不会得到一个以上的点(因为*的匹配算法在mmv不是贪婪的),然而,它处理()'正确的”。 例:

 $ mmv -v "*.*" "#1.#l2" FOO.BAR.MP3 -> FOO.bar.mp3 : done foo bar 'baz' (CD 1).MP3 -> foo bar 'baz' (CD 1).mp3 : done 

不完美,但比使用find/exec/sed东西更容易使用和记忆。

递归地为所有一个好解决方案:

 find -name '*.JPG' | sed 's/\(.*\)\.JPG/mv "\1.JPG" "\1.jpg"/' |sh 

上面递归地将扩展名为“JPG”的文件重命名为扩展名为“jpg”的文件

如果你使用ZSH:

 zmv '(*).(*)' '$1.$2:l' 

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

 autoload -U zmv 

然后再试一次。

感谢这篇关于zmv的技巧文章和小写/大写替换语法的ZSH文档 。

所以,看起来像线噪声的这些解决方案是很好的,所有,但是这是很容易做从蟒蛇REPL(我知道的OP要求bash,但python安装在很多系统上,这些天bash … ):

 import os files = os.listdir('.') for f in files: path, ext = os.path.splitext(f) if ext.isupper(): os.rename(f, path + ext.lower()) 

如果您只对某些文件扩展名感兴趣,例如将所有较高大小写的“JPG”扩展名转换为小写“jpg”,则可以使用命令行实用程序重命名 。 CD到您想要更改的目录中。 然后

 rename -n 's/\.JPG$/\.jpg/' * 

使用-n选项来测试将要改变的内容,然后当你喜欢的结果使用没有这样的

 rename 's/\.JPG$/\.jpg/' *