尝试在递归目录中重命名某些文件类型

时间:2017-01-05 19:06:29

标签: bash macos directory sh batch-rename

我在目录结构中有一堆文件:

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合并到代码中。

非常感谢任何帮助。

4 个答案:

答案 0 :(得分:2)

使用Perl的重命名(独立命令):

shopt -s globstar
rename -n 's|/[0-9]{7}_([^/]+$)|/$1|' **/*

如果一切正常,请删除-n

  

globstar:如果设置,路径名扩展上下文中使用的模式**将会                         匹配所有文件和零个或多个目录和子目录。如果                         该模式后跟一个/,只有目录和子目录                         匹配。

答案 1 :(得分:0)

['.../python/lib/python2.7/site-packages/ipykernel/__main__.py', '-f', '.../.local/share/jupyter/runtime/kernel-fd79e9d9-d66f-4cf6-856b-a4a3c3ea73a0.json'] 确实提供了函数,这些函数可以递归,但是您不需要为此作业提供递归函数。您只需要枚举树中的所有文件。 bash命令可以执行此操作,但启用find的{​​{1}}选项并使用shell glob来执行此操作更安全:

bash

请注意,这不会验证文件名是否与执行重命名之前指定的模式实际匹配;我带你去听你的话。如果需要这样的检查,那么肯定可以添加。

答案 2 :(得分:0)

对你已经拥有的这个小调整怎么样:

for i in `find . -type f`; do mv "$i" "$(echo $i | cut -d_ -f2-10)"; done

基本上只是用`find来交换*。 -type f`

答案 3 :(得分:0)

应该可以使用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 v4 extglob提供更好的文件名匹配,并globstar通过子目录进行递归。

希望这些帮助。