AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / ubuntu / 问题 / 671320
Accepted
don.joey
don.joey
Asked: 2015-09-08 05:40:07 +0800 CST2015-09-08 05:40:07 +0800 CST 2015-09-08 05:40:07 +0800 CST

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

  • 772

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

Screenshot 2015-09-07-25:10:10

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

这些文件可以重命名为

Screenshot 2015-09-07-25--10--10

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

以下列表是保留字符:

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

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

filesystem
  • 3 3 个回答
  • 7597 Views

3 个回答

  • Voted
  1. Best Answer
    muru
    2015-09-08T05:48:02+08:002015-09-08T05:48:02+08:00

    你可以这样做:

    rename 's/[<>:"\\|?*]/_/g' /path/to/file
    

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

    find /path/to/directory -depth -exec rename 's/[<>:"\\|?*]/_/g' {} +
    

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

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

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

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

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

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

    #! /bin/bash
    
    windows_chars='<>:"\|?*'
    prefix="windows/"
    
    # Find number of files/directories which has this name as a prefix
    find_num_files ()
    (
        if [[ -e $prefix$1$2 ]]
        then
            shopt -s nullglob
            files=( "$prefix$1-"*"$2" )
            echo ${#files[@]}
        fi
    )
    
    # From http://www.shell-fu.org/lister.php?id=542
    # Joins strings with a separator. Separator not present for
    # edge case of single string.
    str_join ()
    (
        IFS=${1:?"Missing separator"}
        shift
        printf "%s" "$*"
    )
    
    for i
    do
        # convert to lower case, then replace special chars with _
        new_name=$(tr "$windows_chars" _ <<<"${i,,}")
    
        # if a directory, make it, instead of copying contents
        if [[ -d $i ]]
        then
            mkdir -p "$prefix$new_name"
            echo mkdir -p "$prefix$new_name"
        else
            # get filename without extension
            name_wo_ext=${new_name%.*}
            # get extension
            # The trick is to make sure that, for:
            # "a.b.c", name_wo_ext is "a.b" and ext is ".c"
            # "abc", name_wo_ext is "abc" and ext is empty
            # Then, we can join the strings without worrying about the
            # . before an extension
            ext=${new_name#$name_wo_ext}
            count=$(find_num_files "$name_wo_ext" "$ext")
            name_wo_ext=$(str_join - "$name_wo_ext" $count)
            cp "$i" "$prefix$name_wo_ext$ext"
            echo cp "$i" "$prefix$name_wo_ext$ext"
        fi
    done
    

    在行动中:

    $ 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
    

    该脚本在我的 Github 存储库中可用。

    • 9
  2. Jacob Vlijm
    2015-09-08T11:20:52+08:002015-09-08T11:20:52+08:00

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

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

    替换在列表中定义:(chars见下文)。可以为每个字符串提供自己的替换,以便在您想要这样做时能够撤销重命名。(假设替换是一个唯一的字符串)。如果您想用下划线替换所有有问题的字符串,只需定义如下列表:

    chars = [
        ("<", "_"),
        (">", "_"),
        (":", "_"),
        ('"', "_"),
        ("/", "_"),
        ("\\", "_"),
        ("|", "_"),
        ("?", "_"),
        ("*", "_"),
        ]
    

    骗子

    为防止名称重复,脚本首先创建“新”名称。然后它会检查同一目录中是否已存在名称相似的文件。如果是这样,它会创建一个新名称,前面加上dupe_1or dupe_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)
    

    如何使用

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

      python3 /path/to/rename_chars.py <directory_to_rename>
      

    笔记

    请注意,在该行中:

    ("\\", "_bsl_"),
    

    在 python 中,一个反斜杠需要被另一个反斜杠转义。

    • 3
  3. conualfy
    2020-03-30T03:34:08+08:002020-03-30T03:34:08+08:00

    我认为上述解决方案可能有效,但您有另一种情况:ext 文件系统允许更长的文件名和文件夹名。您还必须考虑名称的长度,并使用某种算法对它们进行中继,在名称重复的情况下在最后添加数字或其他内容。

    • 0

相关问题

  • 当另一个文件系统安装在路径上时是否可以删除文件?

  • “/var/lib/dpkg/updates”文件夹中存储了什么?

  • 如何使文件夹与外部 USB 硬盘保持同步?

  • 为什么 Ubuntu 不再将文件大小单位测量为字节、兆字节、千兆字节等?

  • 如何避免启动时出现“S to Skip”消息?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何运行 .sh 脚本?

    • 16 个回答
  • Marko Smith

    如何安装 .tar.gz(或 .tar.bz2)文件?

    • 14 个回答
  • Marko Smith

    如何列出所有已安装的软件包

    • 24 个回答
  • Marko Smith

    无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗?

    • 25 个回答
  • Martin Hope
    Flimm 如何在没有 sudo 的情况下使用 docker? 2014-06-07 00:17:43 +0800 CST
  • Martin Hope
    Ivan 如何列出所有已安装的软件包 2010-12-17 18:08:49 +0800 CST
  • Martin Hope
    La Ode Adam Saputra 无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗? 2010-11-30 18:12:48 +0800 CST
  • Martin Hope
    David Barry 如何从命令行确定目录(文件夹)的总大小? 2010-08-06 10:20:23 +0800 CST
  • Martin Hope
    jfoucher “以下软件包已被保留:”为什么以及如何解决? 2010-08-01 13:59:22 +0800 CST
  • Martin Hope
    David Ashford 如何删除 PPA? 2010-07-30 01:09:42 +0800 CST

热门标签

10.10 10.04 gnome networking server command-line package-management software-recommendation sound xorg

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve