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
在do
和done
之间,它一次查看一个文件,当前文件的名称在参数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 正则表达式重命名文件的主要内容,如果未能解决你的问题,请参考以下文章