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

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

1461758015598.txt --> 1461758015.txt

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

【问题讨论】:

标签: regex bash rename


【解决方案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。

【讨论】:

    猜你喜欢
    • 2020-01-19
    • 2018-11-12
    • 2013-08-06
    • 2020-08-13
    • 2012-08-31
    • 2011-09-14
    • 2017-08-10
    • 1970-01-01
    相关资源
    最近更新 更多