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

1 linux scripting rename

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

    ID_EDMSCP_20160815.txt.pgp
    ID_EDMSCP_20160816.txt.pgp
    ID_EDMSCP_20160817.txt.pgp
    ID_EDMSCP_20160818.txt.pgp       
Run Code Online (Sandbox Code Playgroud)

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

    for file in ID_EDMSCP_*.txt.pgp
    do
        mv -i "${file}" "${file/-ID-/-SUBMIT_GO_ID-}"
    done
Run Code Online (Sandbox Code Playgroud)

但是,我得到以下信息:

    mv: `ID_EDMSCP_20160815.txt.pgp' and `ID_EDMSCP_20160815.txt.pgp' are the same file
Run Code Online (Sandbox Code Playgroud)

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

War*_*ung 6

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

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

mv -i "${file}" "${file/ID_/SUBMIT_GO_ID_}"
Run Code Online (Sandbox Code Playgroud)

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

如果您不能使用高级 shell 的这个非标准功能,还有很多选择:

sed

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

mv -i "$file" "$(echo $file | sed -e 's/^ID_/SUBMIT_GO_ID_/')"
Run Code Online (Sandbox Code Playgroud)

由于使用了$()样式命令插值,这仍然至少需要一个 POSIX shell,但这比期望无处不在的高级 shell 更容易“询问”。

如果您的脚本必须在所有 Bourne 类型的 shell 上运行,您可以切换到反引号样式命令插值,如果您在文件名中嵌入了空格,这可能会很棘手,但这里似乎并非如此,根据您发布的示例。因此,就您的目的而言,这应该等同于先前的选项:

mv -i "$file" `echo $file | sed -e s/^ID_/SUBMIT_GO_ID_/`
Run Code Online (Sandbox Code Playgroud)

毫米波

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

$ mmv 'ID_*' 'SUBMIT_GO_ID_#1'
Run Code Online (Sandbox Code Playgroud)

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

改名

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

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

$ rename '^ID_' SUBMIT_GO_ID_ ID_EDMSCP_*.txt.pgp
Run Code Online (Sandbox Code Playgroud)

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

$ rename ID_ SUBMIT_GO_ID_ ID_EDMSCP_*.txt.pgp
Run Code Online (Sandbox Code Playgroud)

mmv,rename不支持-i标志。

普通的老伯恩壳

说了这么多,您的特定情况允许更简单的解决方案,因为您的输入模式出现在输出模式的尾端,因此您可以使用可移植的 Bourne shell 语法完成所有操作:

for file in ID_EDMSCP_*.txt.pgp
do
    mv -i "$file" SUBMIT_GO_"$file"
done
Run Code Online (Sandbox Code Playgroud)

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