我有一堆文件,它们只是Unix时间戳。问题在于它们的文件名是以毫秒为单位的,而扫描目录的程序希望它们以秒为单位。因此,我需要重命名所有文件,删除.txt扩展名前面的最后3个数字。例如:
1461758015598.txt --> 1461758015.txt
我对正则表达式和Bash不熟悉,所以不知道该如何操作。
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 指出的那样,如果您运行超过一次,它将继续从文件名中删除数字,因此不要这样做。您可以通过收紧全局模式来使其幂等。这有点笨重:
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
ls +([0-9]).txt | egrep ...
的extglob可能更安全,并且在非常大的目录中性能更高。 - ghotiMark的答案涵盖了许多选项。
但是,如果您想要递归的东西,我会选择像这样基于find
的解决方案:
find -E . -regex '.*/[0-9]{13}\.txt' -exec \
sh -c 'set -; mv -v "$0" "${0%???.txt}.txt"' "{}" \;
注意:
-E
选项,告诉-regex
使用ERE。如果您使用的是旧操作系统,则可能需要将ERE转换为BRE。${..%..}
而不是${../../}
,使其符合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。