Как переименовать имена файлов для предотвращения конфликта в Windows или Mac?

Как может я обрабатывать в пакетном режиме переименовать имена файлов так, чтобы они не включали символы, которые сталкиваются с другими файловыми системами что касается экземпляра,

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

Обратите внимание, что двоеточия являются проблемой в этом имени файла. Они не будут переварены Windows или Mac.

Эти файлы могли быть переименованы к

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

Я должен переместить большую сумму файлов от Ubuntu до другой ОС. Я скопировал их в использование диска NTFS Rsync, но это потеряло некоторые файлы. Я также скопировал их в диск ext4.

Следующий список является зарезервированными символами:

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

Другая проблема - то, что Windows не чувствителен к регистру когда дело доходит до имен файлов, (и большинство систем OS X также).

5
задан 27 September 2016 в 02:34

3 ответа

Вы могли сделать что-то как:

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

Это заменит все эти символы a _. Обратите внимание, что Вы не должны заменять /, так как это - недопустимый символ для имен файлов в обеих файловых системах, но используется в качестве разделителя пути 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 repo.

6
ответ дан 23 November 2019 в 08:55

Рекурсивно замените список строк или символов в именах файлов другими строками или символов

Сценарий ниже может использоваться для замены списка строк или символов, возможно происходящих на имя файла, произвольной заменой на строку. Так как сценарий только переименовывает сам файл (не путь), нет никакого риска питания с каталогами.

Замена определяется в списке: chars (см. далее ниже). Возможно дать каждой строке свою собственную замену, смочь инвертировать переименование, если Вы когда-либо хотели бы сделать это. (принятие замены является уникальной строкой). В случае, если требуется заменить все проблематичные строки подчеркиванием, просто определите список как:

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

Простофили

Для предотвращения дублированных имен сценарий сначала создает "новое" имя. Это затем проверяет, существует ли столь же именованный файл уже в том же каталоге. Если так, это создает новое имя, которому предшествуют dupe_1или dupe_2, пока это не находит "доступное" новое название файла:

enter image description here

становится:

enter image description here

Сценарий

#!/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
ответ дан 23 November 2019 в 08:55

Я думаю, что приведенные выше решения могут сработать, но у вас другой случай: файловая система ext допускает более длинные имена файлов и имена папок. Вы также должны учитывать длину имен и соединять их с помощью некоторого алгоритма, добавляя числа или что-то в конце в случае повторяющихся имен.

0
ответ дан 29 March 2020 в 11:34

Другие вопросы по тегам:

Похожие вопросы: