将所有的文件扩展名小写 [英] Convert all file extensions to lower-case

查看:173
本文介绍了将所有的文件扩展名小写的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想小写不管它是什么我所有的扩展。到目前为止,从我所看到的东西,你必须指定要转换为小写什么文件扩展名。不过,我只是想为小写一切第一个最后一个点在名称后。

I'm trying to lower-case all my extensions regardless of what it is. So far, from what I've seen, you have to specify what file extensions you want to convert to lower-case. However, I just want to lower-case everything after the first last dot . in the name.

我怎样才能做到这一点在庆典

How can I do that in bash?

推荐答案

解决方案

您可以解决的任务在一行中:

You can solve the task in one line:

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

注:这将打破对包含换行符的文件名。但我承担了。

Note: this will break for filenames that contain newlines. But bear with me for now.

使用示例

$ 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 ),并为每个文件运行命令*。*:

You find all files in current directory (.) that have period . in its name (-name '*.*') and run the command for each file:

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

这意味着命令:尝试转换文件的扩展名改为小写(这使得 SED

That command means: try to convert file extension to lowercase (that makes 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

If something was changed [ "$a" != "$0" ], rename the file mv "$0" "$a".

正在处理的文件的名称( {} )传递到 SH -c 作为其额外的参数,可以看出在命令行 $ 1,0 里面。
它使脚本安全的,因为在这种情况下,外壳采取{}为数据,而不是作为一个$ C $的c-部分,因为当其在命令行直接指定。
感谢的@gniourf_gniourf的在这个非常重要的问题指着我的)。

The name of the file being processed ({}) passed to sh -c as its additional argument and it is seen inside the command line as $0. It makes the script safe, because in this case the shell take {} as a data, not as a code-part, as when it is specified directly in the command line. (I thank @gniourf_gniourf for pointing me at this really important issue).

正如你所看到的,如果你使用 {} 直接在脚本,
它可能有
一些壳注射的文件名,是这样的:

As you can see, if you use {} directly in the script, it's possible to have some shell-injections in the filenames, something like:

; rm -rf * ;

在这种情况下,注入将由壳被视为一个部分
在code,他们将被执行。

In this case the injection will be considered by the shell as a part of the code and they will be executed.

虽然版本

清晰,但稍微长一点,脚本的版本:

Clearer, but a little bit longer, version of the script:

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

这还是打破了包含换行符的文件名。要解决这个问题,你需要有一个找到支持 -print0 (如GNU 找到)和Bash(让支持 -d 分界开关):

This still breaks for filenames containing newlines. To fix this issue, you need to have a find that supports -print0 (like GNU find) and Bash (so that read supports the -d delimiter switch):

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

这还是打破对于包含尾随换行符(因为它们将由 A = $(...)子shell。如果你的真正<被吸收的文件/ em>的希望有一个简单的方法(你应该!),用最新版本的Bash(Bash≥4.0)的支持 ,, 参数扩展,这里的终极解决方案:

This still breaks for files that contain trailing newlines (as they will be absorbed by the a=$(...) subshell. If you really want a foolproof method (and you should!), with a recent version of Bash (Bash≥4.0) that supports the ,, parameter expansion here's the ultimate solution:

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

返回到原来的解决方案

或者在一个找到去(回一些修正原来的解决方案,使得它真正做到万无一失):

Or in one find go (back to the original solution with some fixes that makes it really foolproof):

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

我添加型的F 这样只有普通文件被重命名。没有这一点,你仍存在问题,如果目录名文件名之前重命名。如果你也想重​​命名目录(和链接,管道等),你应该使用 -depth

I added -type f so that only regular files are renamed. Without this, you could still have problems if directory names are renamed before file names. If you also want to rename directories (and links, pipes, etc.) you should use -depth:

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

找到进行深度优先搜索。

您可能会说,这不是有效的产卵找到的每个文件中的庆典过程。这是正确的,然后previous环路版本会更好。

You may argue that it's not efficient to spawn a bash process for each file found. That's correct, and the previous loop version would then be better.

这篇关于将所有的文件扩展名小写的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆