我有一个大型 unix 文件服务器,带有一个大型 SMB 共享。它为 Mac、Linux 和 Windows 客户端提供服务。此机器上的大部分文件已从 Mac Xserve 迁移到那里。备份共享的方法之一是通过 Windows 机器。如果文件名中有它不喜欢的字符,该特定备份软件就会失败。
我已设法修复了大多数文件名问题,但对以点结尾的文件仍感到困扰。例如:
filename.
newfile.txt.
stupid old file.
我正在尝试找到一种方法来批量重命名所有以点结尾的文件,使其不带点。因此filename.
变成filename
find . -name "*."
可以找到文件。我尝试通过 sed 进行管道传输:
find . -name "*." | sed 's/.$//'
它可以在控制台中完成任务,但实际上不会重命名文件。这就是我遇到的问题。
答案1
如果您有 Perl 脚本版本rename
(称为rename
或prename
):
rename 's/\.$//' *.
或者 util-linux 版本(称为rename
或rename-ul
):
rename . '' *.
如果您运行不带参数的命令并得到类似以下内容:
用法:重命名 [-v] [-n] [-f] perlexpr [文件名]
那么它是 Perl 脚本版本。
就像是:
rename.ul:参数不足
用法:rename.ul [选项] 表达式替换文件...
选项:-v,--verbose 解释正在执行的操作 -V,--version
输出版本信息并退出 -h,--help 显示此帮助并退出
表示它是 util-linux 版本。
答案2
有点黑客但应该可以工作:
如果要重命名带有尾随点的文件和目录:
find . -name "*." -print0 | xargs -0 -n 1 my_rename.sh
或者如果您只想重命名文件:
find . -name "*." -type f -print0 | xargs -0 -n 1 my_rename.sh
脚本如下my_rename.sh
:
#!/bin/bash
mv "$1" "${1%%.}"
(另外不要忘记使脚本可执行: chmod +x my_rename.sh
)2
答案3
这看起来应该可以完成这个工作:
find . -type f -name '*\.' -exec bash -c 'mv "$1" "${$1%.}"' _ {} \;
这将 find 限制为仅以句点结尾的文件(否则它将匹配当前工作目录“。”),然后mv "$1" "${$1%.}"
对找到的每个文件名执行带引号的 shell 代码片段 ( )。在 shell 代码片段中,它使用 bash 参数扩展和替换来删除尾随的“。”。末尾的另一行 noise 是 find -exec 所必需的:{}
是 find 中匹配的文本,\;
是结束 exec 字符串所必需的,我相信它_
告诉 exec 将 {} 作为参数 ( $1
) 传递给sh
命令。说实话,-exec 的这种特定用法对我来说很新奇,我发现它这里。
bash 替换位非常简单,我经常使用它来重命名文件,例如FILENAME=foo.JPG; mv ${FILENAME} ${FILENAME%.JPG}.jpg
从 FILENAME 中删除“.JPG”并将其替换为“.jpg”
如果您仍然想使用 sed 而不是 bash 扩展,这看起来可以完成这项工作:
find . -type f -name '*\.' -exec sh -c 'mv "{}" "$(echo {} | sed s/\.$// )"' \;
-exec
我首先尝试在不调用的情况下解决这个问题sh -c
,但这并不像在尝试执行 sed 时扩展 {}(或使用之前的 bash 替换示例)。
还请注意,您必须在要扩展的文件名周围加上“ ” (例如,{} 或 $1,具体取决于示例),因为您的示例文件中有空格。这仍可能中断,具体取决于文件中的特殊字符 (例如,文件名中的“ 会导致问题)。