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

唐·乔伊

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

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

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

这些文件可以重命名为

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

我必须将大量文件从Ubuntu移至另一个OS。我使用Rsync将它们复制到NTFS驱动器,但是丢失了一些文件。我也将它们复制到ext4驱动器。

以下列表是保留字符:

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

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

muru

您可以执行以下操作:

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存储库中找到

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章