2016-04-27 158 views
3

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

1461758015598.txt - > 1461758015.txt

我是新来的正则表达式和bash,所以我不知道如何做到这一点。

+0

一故障保护python的替代工作递归:http://stackoverflow.com/a/39698169/191246 – ccpizza

回答

3

这里有一种方法:

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 
+4

OP需要只运行它一次,或者它也会重命名“1461758015.txt”为“1461758.txt”,然后“1461758.txt 'to'1461.txt' – anubhava

+0

If OP的使用bash无论如何都是使用'ls +([0-9]).txt |的extglob egrep ...'可能更安全,而且在大型目录中性能更高。 – ghoti

0

马克的回答涵盖了多种选择。

但是,如果你想要的东西递归,我会用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