我在一个目录结构中有一堆文件,例如:
Dir
SubDir
File
File
Subdir
SubDir
File
File
File
很抱歉格式混乱,但正如你所看到的,有不同目录级别的文件。所有这些文件名后面都附加了一个由7个数字组成的字符串,例如:1234567_filename.ext。我正在尝试删除文件名开头的数字和下划线。
现在我正在使用bash,并使用这个oneliner使用mv和cut:重命名文件
for i in *; do mv "$i" "$(echo $i | cut -d_ -f2-10)"; done
这是在我CD插入目录时运行的。我很想找到一种递归的方法,这样它只重命名文件,而不是文件夹。我还在shell中使用了foreach循环,在bash之外,用于那些有一堆文件夹的目录,其中有文件,没有其他子目录:
foreach$ set p=`echo $f | cut -d/ -f1`
foreach$ set n=`echo $f | cut -d/ -f2 | cut -d_ -f2-10`
foreach$ mv $f $p/$n
foreach$ end
但只有当文件夹中没有其他子目录时,这才有效。
有没有一个循环或oneliner可以用来重命名目录中的所有文件?我甚至尝试使用find
,但不知道如何将cut
合并到代码中。
非常感谢您的帮助。
使用Perl的重命名(独立命令):
shopt -s globstar
rename -n 's|/[0-9]{7}_([^/]+$)|/$1|' **/*
如果一切看起来都很好,请删除-n
。
globstar
:如果设置,路径名扩展上下文中使用的模式**将匹配所有文件以及零个或多个目录和子目录。如果该模式后面跟着一个/,只有目录和子目录火柴
bash
确实提供了函数,这些函数可以是递归的,但您不需要递归函数来完成此任务。您只需要枚举树中的所有文件。find
命令可以做到这一点,但打开bash
的globstar
选项并使用shell glob更安全:
#!/bin/bash
shopt -s globstar
# enumerate all the files in the tree rooted at the current working directory
for f in **; do
# ignore directories
test -d "$f" && continue
# separate the base file name from the path
name=$(basename "$f")
dir=$(dirname "$f")
# perform the rename, using a pattern substitution on the name part
mv "$f" "${dir}/${name/#???????_/}"
done
请注意,这并不能验证文件名是否与执行重命名之前指定的模式匹配;我相信你的话,他们确实这么做了。如果需要这样的支票,那么肯定可以添加。
对您现有的进行这个小调整怎么样
for i in `find . -type f`; do mv "$i" "$(echo $i | cut -d_ -f2-10)"; done
基本上只是用find替换*-类型f`
应该可以使用find
。。。
find -E . -type f
-regex '.*/[0-9]{7}_.*.txt'
-exec sh -c 'f="${0#*/}"; mv -v "$0" "${0%/*}/${f#*_}"' {} ;
您的find
选项可能有所不同——我在FreeBSD中这样做。这里的想法是:
-E
指示find
使用扩展正则表达式-type f
导致只能找到正常的文件(而不是目录或符号链接)-regex ...
与您要查找的文件相匹配。如果需要的话,你可以更具体一些exec ... ;
运行一个命令,使用{}
(我们找到的文件)作为参数
我们正在运行的命令首先使用参数扩展来获取目标目录,然后删除文件名。请注意临时变量$f
,它用于解决额外下划线成为文件名一部分的可能性。
请注意,这不是一个bash
命令,尽管您当然可以从bash shell运行它。如果您想要一个不需要使用像find
这样的外部工具的bash解决方案,您可以执行以下操作:
$ shopt -s extglob # use extended glob format
$ shopt -s globstar # recurse using "**"
$ for f in **/+([0-9])_*.txt; do f="./$f"; echo mv "$f" "${f%/*}/${f##*_}"; done
这使用与find
解决方案相同的逻辑,但使用bash v4extglob
提供更好的文件名匹配,并使用globstar
在子目录中递归。
希望这些帮助。