以下是我需要重命名的文件的一小部分示例:
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
与 一样mmv
,rename
不支持该-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