如何重命名数百个文件,使其在文件名开头都包含相同的单词?

如何重命名数百个文件,使其在文件名开头都包含相同的单词?

以下是我需要重命名的文件的一小部分示例:

    ID_EDMSCP_20160815.txt.pgp
    ID_EDMSCP_20160816.txt.pgp
    ID_EDMSCP_20160817.txt.pgp
    ID_EDMSCP_20160818.txt.pgp       

我根据别人的问题创建了一个脚本,如下所示:

    for file in ID_EDMSCP_*.txt.pgp
    do
        mv -i "${file}" "${file/-ID-/-SUBMIT_GO_ID-}"
    done

但是,我得到以下信息:

    mv: `ID_EDMSCP_20160815.txt.pgp' and `ID_EDMSCP_20160815.txt.pgp' are the same file

并且没有任何东西被重命名。我错过了什么吗?

答案1

mv -i "${file}" "${file/-ID-/-SUBMIT_GO_ID-}"

该字符串替换告诉它要替换-ID-,这不会出现在源文件名中。我想你的意思是这样说:

mv -i "${file}" "${file/ID_/SUBMIT_GO_ID_}"

您可能遇到的另一个问题是,这是一项ksh93功能,在 Bash 和 Zsh 中也可用,但是不在纯 POSIX shell 中。如果您#!/bin/sh在脚本的顶部使用,它将在 POSIX shell 或 POSIX 之前的 Bourne shell 解释器下运行在某些系统上,这不会理解。

如果您无法使用高级 shell 的这种非标准功能,还有很多替代方案:

sed

如果您需要将此脚本移植到所有 Unix 类型系统,您可以切换到sed替换:

mv -i "$file" "$(echo $file | sed -e 's/^ID_/SUBMIT_GO_ID_/')"

由于使用了$()样式命令插值,这仍然至少需要一个 POSIX shell,但这比期望到处都有高级 shell 更容易“提出”。

如果您的脚本必须在每个 Bourne 类型的 shell 上运行,您可以切换到反引号样式的命令插值,如果文件名中嵌入了空格,则可能很难正确执行,但根据您发布的示例,这里似乎并非如此。因此,对于您的目的,这应该等同于前一个选项:

mv -i "$file" `echo $file | sed -e s/^ID_/SUBMIT_GO_ID_/`

毫米波

另一种选择是安装mmv,该程序并未安装在我所知道的任何 Unix 类型系统上,但通常将其打包在标准包存储库中。使用mmv,您可以将整个 shell 脚本循环替换为

$ mmv 'ID_*' 'SUBMIT_GO_ID_#1'

请注意,没有-i标志,因为mmv不支持要求每次重命名。但是,它会预先检查所有计划的重命名,并尝试在开始工作之前检测问题,因此它可能足够接近您的目的。

改名

还有一个选项是rename命令,该命令至少存在三种变体。有 叉子Larry Wall 的同名 Perl 脚本,其中一个脚本可能已经作为 Perl 发行版的一部分安装在您的系统上。然后是util-linux变体,通常要么安装在 Linux 机器上而不是该版本,要么安装在它旁边。如果两者都安装了,则可能会调用基于 Perl 的版本prename以避免冲突。

基于 Perl 的主要优点是您可以使用Perl正则表达式mmv,它比 所支持的 glob 表达式或 所支持的 POSIX 正则表达式更强大sed。然而,在这个特定的例子中,这并不重要,因为任务很简单:

$ rename '^ID_' SUBMIT_GO_ID_ ID_EDMSCP_*.txt.pgp

util-linux版本的功能要弱得多,因为尽管它将第一个参数称为“表达式”,但它既不是 POSIX 正则表达式,也不是 Perl 正则表达式。它甚至不是一个全局表达式:它只是一个文字字符串。但如上所述,在这种特殊情况下,这种限制实际上并不会妨碍我们:

$ rename ID_ SUBMIT_GO_ID_ ID_EDMSCP_*.txt.pgp

与 一样mmvrename不支持该-i标志。

普通旧伯恩贝壳

综上所述,您的特定情况允许更简单的解决方案,因为您的输入模式出现在输出模式的末尾,因此您可以使用可移植的 Bourne shell 语法来完成这一切:

for file in ID_EDMSCP_*.txt.pgp
do
    mv -i "$file" SUBMIT_GO_"$file"
done

我在上面留下了复杂的替代方案,因为它们通常是必要的,因为 shell 语言中的内部机制并不总是足够的。

答案2

尝试这个:

for file in ID_EDMSCP_*.txt.pgp
do
    mv -i "${file}" SUBMIT_GO_"${file}"
done

答案3

在Linux下,您可以使用rename命令。它非常有限,但对于这个简单的用例来说已经足够了:用不同的字符串替换第一次出现的子字符串。

rename ID SUBMIT_GO_ID ID_EDMSCP_*.txt.pgp

在 Debian 及其衍生版本(Ubuntu、Mint 等)上,该命令称为rename.ul.这些发行版上的命令rename是不同的命令,具有不兼容的语法,也称为prename。使用该命令你可以做

prename 's/ID/SUBMIT_GO_ID/' ID_EDMSCP_*.txt.pgp

相关内容