Совместимость файлов и файлов с Windows [duplicate]

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

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 в 12:34

4 ответа

Вы можете сделать что-то вроде:

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

Более полное решение должно, по крайней мере:

Преобразовать все символы в в том же случае Используйте системную систему подсчета

То есть 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.

5
ответ дан 18 July 2018 в 10:04

Вы можете сделать что-то вроде:

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

Более полное решение должно, по крайней мере:

Преобразовать все символы в в том же случае Используйте системную систему подсчета

То есть 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.

5
ответ дан 24 July 2018 в 19:30

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

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

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

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

Dupes

Чтобы предотвратить дублирование имен, скрипт сначала создает " новое имя. Затем он проверяет, существует ли аналогичный файл уже в одном каталоге. Если это так, оно создает новое имя, которому предшествуют dupe_1 или 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)

Как использовать

Скопировать сценарий в пустой файл, сохранить это как rename_chars.py. Измените, если вам нужен список заметок. Как бы то ни было, scrip0t заменяет все вхождения проблемных символов символом подчеркивания, но выбор за вами. Протестируйте его в каталоге с помощью команды: python3 /path/to/rename_chars.py <directory_to_rename>

Примечание

Обратите внимание, что в строке:

("\\", "_bsl_"),

в python обратная косая черта должен быть экранирован другой обратной косой чертой.

2
ответ дан 18 July 2018 в 10:04

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

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

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

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

Dupes

Чтобы предотвратить дублирование имен, скрипт сначала создает " новое имя. Затем он проверяет, существует ли аналогичный файл уже в одном каталоге. Если это так, оно создает новое имя, которому предшествуют dupe_1 или 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)

Как использовать

Скопировать сценарий в пустой файл, сохранить это как rename_chars.py. Измените, если вам нужен список заметок. Как бы то ни было, scrip0t заменяет все вхождения проблемных символов символом подчеркивания, но выбор за вами. Протестируйте его в каталоге с помощью команды: python3 /path/to/rename_chars.py <directory_to_rename>

Примечание

Обратите внимание, что в строке:

("\\", "_bsl_"),

в python обратная косая черта должен быть экранирован другой обратной косой чертой.

2
ответ дан 24 July 2018 в 19:30

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

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