如何重命名文件名以避免在 Windows 或 Mac 中发生冲突?

don*_*oey 7 filesystem files rsync cp

如何批量重命名文件名,以便它们不包含与其他文件系统冲突的字符,例如,

Screenshot 2015-09-07-25:10:10
Run Code Online (Sandbox Code Playgroud)

请注意,冒号是此文件名中的问题。这些不会被 Windows 或 Mac 消化。

这些文件可以重命名为

Screenshot 2015-09-07-25--10--10
Run Code Online (Sandbox Code Playgroud)

我必须将大量文件从 Ubuntu 移动到另一个操作系统。我使用 Rsync 将它们复制到 NTFS 驱动器,但丢失了一些文件。我还将它们复制到 ext4 驱动器。

以下列表是保留字符:

< (less than)
> (greater than)
: (colon)
" (double quote)
/ (forward slash)
\ (backslash)
| (vertical bar or pipe)
? (question mark)
* (asterisk)
Run Code Online (Sandbox Code Playgroud)

另一个问题是 Windows 在文件名方面不区分大小写(以及大多数 OS X 系统)。

mur*_*uru 9

你可以这样做:

rename 's/[<>:"\\|?*]/_/g' /path/to/file
Run Code Online (Sandbox Code Playgroud)

这会将所有这些字符替换为_. 请注意,您不需要替换/,因为它是两个文件系统中文件名的无效字符,但用作 Unix 路径分隔符。扩展到一个目录及其所有内容:

find /path/to/directory -depth -exec rename 's/[<>:"\\|?*]/_/g' {} +
Run Code Online (Sandbox Code Playgroud)

请注意,两者/(标志着模式的结束)和\都被转义了。为了保持唯一性,您可以为其附加一个随机前缀:

$ rename -n 's/[<>:"\/\\|?*]/_/g && s/^/int(rand(10000))/e' a\\b
a\b renamed as 8714a_b
Run Code Online (Sandbox Code Playgroud)

一个更完整的解决方案至少应该:

  1. 将所有字符转换为相同大小写
  2. 使用合理的计数系统

也就是说,foo.mp3不应该变成foo.mp3.1,但是foo.1.mp3,因为 Windows 更依赖于扩展。

考虑到这一点,我编写了以下脚本。我试图通过使用前缀路径来实现非破坏性,我可以将重命名的文件复制到其中,而不是修改原始文件。

rename 's/[<>:"\\|?*]/_/g' /path/to/file
Run Code Online (Sandbox Code Playgroud)

在行动:

$ tree a:b
a:b
??? b:c
?   ??? a:d
?   ??? A:D
?   ??? a:d.b
?   ??? a:D.b
??? B:c
??? B"c
    ??? a<d.b

3 directories, 5 files
$ find a:b -exec ./rename-windows.sh {} +
mkdir -p windows/a_b
mkdir -p windows/a_b/b_c
mkdir -p windows/a_b/b_c
cp a:b/B"c/a<d.b windows/a_b/b_c/a_d.b
mkdir -p windows/a_b/b_c
cp a:b/b:c/a:D.b windows/a_b/b_c/a_d-0.b
cp a:b/b:c/A:D windows/a_b/b_c/a_d
cp a:b/b:c/a:d windows/a_b/b_c/a_d-1
cp a:b/b:c/a:d.b windows/a_b/b_c/a_d-1.b
$ tree windows/
windows/
??? a_b
    ??? b_c
        ??? a_d
        ??? a_d-0.b
        ??? a_d-1
        ??? a_d-1.b
        ??? a_d.b

2 directories, 5 files
Run Code Online (Sandbox Code Playgroud)

该脚本可在我的 Github 存储库中找到


Jac*_*ijm 5

将文件名中的字符串或字符列表递归地替换为其他字符串或字符

下面的脚本可用于通过每个string 的任意替换来替换可能出现在文件名中的字符串或字符列表。由于脚本仅重命名文件本身(而不是路径),因此不存在弄乱目录的风险。

替换在列表中定义:(chars参见下文)。可以为每个字符串提供自己的替换,以便能够反转重命名(如果您愿意的话)。(假设替换是唯一的字符串)。如果您想用下划线替换所有有问题的字符串,只需定义列表,如下所示:

chars = [
    ("<", "_"),
    (">", "_"),
    (":", "_"),
    ('"', "_"),
    ("/", "_"),
    ("\\", "_"),
    ("|", "_"),
    ("?", "_"),
    ("*", "_"),
    ]
Run Code Online (Sandbox Code Playgroud)

骗子

为了防止重复名称,脚本首先创建“新”名称。然后它检查同一目录中是否已存在类似名称的文件。如果是这样,它会创建一个新名称,前面带有dupe_1dupe_2,直到找到该文件的“可用”新名称:

在此输入图像描述

变成:

在此输入图像描述

剧本

#!/usr/bin/env python3
import os
import shutil
import sys

directory = sys.argv[1]

# --- set replacement below in the format ("<string>", "<replacement>") as below
chars = [
    ("<", "_"),
    (">", "_"),
    (":", "_"),
    ('"', "_"),
    ("/", "_"),
    ("\\", "_"),
    ("|", "_"),
    ("?", "_"),
    ("*", "_"),
    ]
# ---

for root, dirs, files in os.walk(directory):
    for file in files:
        newfile = file
        for c in chars:
            newfile = newfile.replace(c[0], c[1])
        if newfile != file:
            tempname = newfile; n = 0
            while os.path.exists(root+"/"+newfile):
                n = n+1; newfile = "dupe_"+str(n)+"_"+tempname
            shutil.move(root+"/"+file, root+"/"+newfile)
Run Code Online (Sandbox Code Playgroud)

如何使用

  1. 将脚本复制到空文件中,另存为rename_chars.py.
  2. 如果您想要替换列表,请进行编辑。实际上,scrip0t 会用下划线替换所有出现的有问题的字符,但选择权在您。
  3. 测试 - 通过以下命令在目录上运行它:

    python3 /path/to/rename_chars.py <directory_to_rename>
    
    Run Code Online (Sandbox Code Playgroud)

笔记

请注意该行中:

("\\", "_bsl_"),
Run Code Online (Sandbox Code Playgroud)

在Python中,一个反斜杠需要用另一个反斜杠来转义。