使用 FIND 和 MV 来重命名文件。删除找到的字符串然后将其添加到文件名中?

使用 FIND 和 MV 来重命名文件。删除找到的字符串然后将其添加到文件名中?
find . -type f -name '*authors-name-string*' -exec bash -c 'mv "$0" "${0/authors-name-string/}"' {} \;

我正在尝试重命名嵌套在多层目录中的文件,这些目录包含在文件名中随机嵌入的作者姓名文本字符串。创建一个新文件名,该文件名以作者姓名开头,后跟原始文件名的其余部分...但没有位于原始文件名中随机位置的作者姓名字符串。

上面的 shell 命令行将从文件名中递归地删除authors-name-text字符串,但我还没有弄清楚如何做到这一点,并将authors-name-text(以及结尾的“_”下划线)添加到开头文件名。基本上我想将作者姓名文本从文件名中当前的位置移动到文件名的开头(加上下划线)。据我所知,我的 Synology NAS 上调用的 bash 版本是 v4.3。我已经从我的 MacBook 通过 ssh 登录。

尝试获取按主题目录名称组织的不同目录中的数千个文件,以便在查看简单的目录列表时,目录中由同一作者编写的某些文件显示为分组在一起。

find . -type f -name '*authors-name-string*' -exec bash -c 'mv "$0" "authors-name-string_${0/authors-name-string/}"' {} \;

当上面的命令行尝试在整个文件名路径的前面插入“authors-name-string_”时会失败。不过,由于没有该名称的起始目录,因此 MV 命令会抱怨,但它仍然会根据需要从文件名中的原始位置删除作者姓名字符串。

答案1

扩展您的方法并利用参数扩展:

export author_string='author1'
export new_string='author1'
find . -type f -name "*${author_string}*" \
  -exec sh -c '
    path="${1%/*}"
    tmp="${1%%${author_string}[^/]*}"
    before="${tmp##*/}"
    after="${1##*${author_string}}"
    echo mv -- "$1" "${path}/${new_string}_${before}${after}"' sh {} \;

我的假设,因为我不确定我完全理解你的问题:

您正在搜索名称包含固定字符串的文件;这里,变量author_string.
您正在重命名目录树中各处的文件。
文件的新名称将以固定字符串开头(相同author_string或不同,没有太大区别);这里,变量new_string.
文件新名称的其余部分将等于其旧名称,但author_string要删除的部分除外。

在此代码中:

  • 我们导出旧/新字符串,以使它们可用于 调用的 shell find

  • 着眼于便携性,-exec调用sh.$1使用 代替$0,如您的代码片段中所示,因为$0通常用于设置 shell/命令的名称。

  • 对于每个文件,我们分割其完整路径:

    • path="${1%/*}"是删除文件名部分的完整路径:${parameter%word}删除与模式匹配的后缀word

    • tmp="${1%%${author_string}[^/]*}"捕获每个文件的完整路径前面的部分author_string${parameter%%word}删除最长与模式匹配的后缀word。我们通常会忽略目录名称中[^/]出现的任何情况;author_string

    • before="${tmp##*/}"仅捕获文件名中的子字符串:${parameter##word}删除与模式匹配的最长前缀word

    • after="${1##*${author_string}}"是文件名后面的部分author_string

  • 我们重命名每个文件。

请注意,如果author_string在文件名中重复,则两次出现之间的任何内容都会丢失。

另外,请记住,如果您想按字面匹配它们,则需要转义(使用\)其中具有特殊模式匹配含义的所有字符。author_string

给定目录树:

$ tree .
.
├── testdir
│   ├── title2_author1_date.book
│   ├── title3_author1_date.book
│   └── title4_author2_date.book
├── title1_author1_date.book
└── title5_author2_date.book

这段代码的作用是:

$ export author_string='author1' new_string='author1'; find . -type f -name "*${author_string}*" -exec sh -c 'path="${1%/*}"; tmp="${1%%${author_string}[^/]*}"; before="${tmp##*/}"; after="${1##*${author_string}}"; echo mv -- "$1" "${path}/${new_string}_${before}${after}"' sh {} \;
mv -- ./title1_author1_date.book ./author1_title1__date.book
mv -- ./testdir/title3_author1_date.book ./testdir/author1_title3__date.book
mv -- ./testdir/title2_author1_date.book ./testdir/author1_title2__date.book

echo当您认为已准备好实际重命名文件时,从命令中删除。


参考:

参数扩展在“The Open Group 基本规范第 7 期,2018 年版”(POSIX.1-2017)

答案2

听起来像是拉里·沃尔的工作rename。请注意还有其他同名命令,这个命令是用 purl 编写的。

相关内容