Bash 正则表达式重命名文件

Posted

技术标签:

【中文标题】Bash 正则表达式重命名文件【英文标题】:Bash Regex rename files 【发布时间】:2016-08-22 09:17:17 【问题描述】:

我有一堆文件只是一个 unix 时间。问题是它们的文件名是millis,而扫描目录的程序希望它们在几秒钟内。所以我需要重命名所有文件以删除 .txt 扩展名之前的最后 3 位数字。即:

1461758015598.txt --> 1461758015.txt

我是 regex 和 bash 的新手,所以我不知道该怎么做。

【问题讨论】:

递归工作的故障安全 python 替代方案:***.com/a/39698169/191246 【参考方案1】:

这是一种方法:

for f in *.txt; do   
  mv "$f" "$f/[0-9][0-9][0-9].txt/.txt"
done

dodone 之间,它一次查看一个文件,当前文件的名称在参数f 中。 "$f" 是该参数的值,未更改。 "$f/[0-9][0-9][0-9].txt/.txt" 是应用了替换的参数值:将“三位数字后跟.txt”替换为仅.txt

正如@anubhava 指出的那样,如果您多次运行它,它会不断从文件名中删除数字,所以不要这样做。您可以通过收紧 glob 模式使其具有幂等性。这有点笨拙:

for f in [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9].txt; do   
  mv "$f" "$f/[0-9][0-9][0-9].txt/.txt"
done

因此您可能希望使用外部工具使其更紧凑(假设目录中的任何文件名中都没有空格或换行符):

for f in $(ls -1 | egrep '^[0-9]13\.txt$'); do 
  mv "$f" "$f/[0-9][0-9][0-9].txt/.txt"
done

您可以通过使用while read 循环将限制减少到“无换行符”:

ls -1 | egrep '^[0-9]13\.txt$' | while read f; do
  mv "$f" "$f/[0-9][0-9][0-9].txt/.txt"
done

【讨论】:

OP 只需要运行一次,否则它还会将1461758015.txt 重命名为1461758.txt,然后将1461758.txt 重命名为1461.txt 如果 OP 仍然使用 bash,带有 ls +([0-9]).txt | egrep ... 的 extglob 可能更安全,并且在非常大的目录中性能更高。【参考方案2】:

马克的回答涵盖了许多选项。

但是,如果您想要递归的东西,我会使用基于 find 的解决方案,如下所示:

find -E . -regex '.*/[0-9]13\.txt' -exec \
  sh -c 'set -; mv -v "$0" "$0%???.txt.txt"' "" \;

注意事项:

我正在使用 FreeBSD,它有一个 -E 选项来告诉 -regex 使用 ERE。如果您使用的是旧版操作系统,则可能需要将 ERE 转换为 BRE。 ERE 坚持使用 13 位数字。如果您多次运行转换,这将使您免于 anubhava 担心会增加衰减。 对于参数扩展,我使用$..%.. 而不是$../../,使这个POSIX 兼容而不是依赖于bash。 (当然,它也可以在 bash 中工作,只是不需要。) 您可能想知道为什么匹配只是去除单个通配符而不是数字。这很好 - 我更容易输入,而且我们已经将文件名约束设置为 find 选项的一部分。

如果您希望避免使用 find 但仍希望在 bash 中进行递归,您可以使用 globstar 选项:

shopt -s globstar extglob
for f in **/+([0-9]).txt; do
  [[ $f =~ ^[0-9]13\.txt$ ]] && mv -v "$f" "$f%...\.txt.txt"
done

请注意,globstar 取决于 bash 版本 4。

【讨论】:

以上是关于Bash 正则表达式重命名文件的主要内容,如果未能解决你的问题,请参考以下文章

在带有 mv 的 bash 中使用正则表达式

使用正则表达式重命名文件 - Linux

正则表达式批量重命名 OS X 终端中的文件

使用正则表达式重命名文件名

python实现对文件批量重命名(用到正则表达式和os.path模块)

使用 python 重命名文件 - 正则表达式