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

Trying to rename certain file types within recursive directories

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

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

但这只有在文件夹中没有其他子目录时才有效。

是否有循环或单行程序可用于重命名目录中的所有文件?我什至尝试使用 find 但无法弄清楚如何将 cut 合并到代码中。

非常感谢任何帮助。

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

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

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

globstar: If set, the pattern ** used in a pathname expansion context will match all files and zero or more directories and subdirectories. If the pattern is followed by a /, only directories and subdirectories match.

bash 确实提供函数,这些函数可以是递归的,但您不需要递归函数来完成这项工作。您只需要枚举树中的所有文件。 find 命令可以做到这一点,但打开 bashglobstar 选项并使用 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 "[=10=]" "${0%/*}/${f#*_}"' {} \;

您的 find 选项可能不同——我在 FreeBSD 中这样做。这里的思路是:

  • -E 指示 find 使用扩展正则表达式。
  • -type f 导致只找到普通文件(不是目录或符号链接)。
  • -regex ... 与您要查找的文件匹配。如果需要,您可以使其更具体。
  • exec ... \; 运行s 一个命令,使用 {}(我们找到的文件)作为参数。

我们 运行ning 的命令首先使用参数扩展来抓取目标目录,然后剥离文件名。请注意临时变量 $f,它用于解决额外下划线成为文件名一部分的可能性。

请注意,这不是 bash 命令,尽管您当然可以从 bash shell 运行 它。如果您想要 bash 不需要使用外部工具(如 find)的解决方案,您可以执行以下操作:

$ 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 递归子目录。

希望这些帮助。