たとえば、他のファイルシステムと競合する文字が含まれないように、ファイル名をバッチで変更するにはどうすればよいですか。
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)
もう1つの問題は、Windowsではファイル名に関して大文字と小文字が区別されないことです(ほとんどのOS Xシステムも同様です)。
次のようなことができます:
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
スクリプトは my Github repo で利用可能です。
以下のスクリプトを使用して、ファイル名に含まれる可能性のある文字列または文字のリストを、文字列ごとの任意の置換で置き換えることができます。スクリプトはファイル自体の名前を変更するだけで(パスではない)、ディレクトリをいじるリスクはありません。
置換はリストで定義されています:chars
(以下を参照)。各文字列に独自の置換を与えて、名前変更を元に戻すことができるようにすることができます。 (置換が一意の文字列であると仮定します)。問題のあるすべての文字列をアンダースコアに置き換える場合は、次のようにリストを定義するだけです。
chars = [
("<", "_"),
(">", "_"),
(":", "_"),
('"', "_"),
("/", "_"),
("\\", "_"),
("|", "_"),
("?", "_"),
("*", "_"),
]
名前の重複を防ぐために、スクリプトは最初に「新しい」名前を作成します。次に、同じ名前のファイルが同じディレクトリに既に存在するかどうかを確認します。その場合、ファイルの「使用可能な」新しい名前が見つかるまで、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
として保存します。次のコマンドを使用して、ディレクトリでテスト実行します。
python3 /path/to/rename_chars.py <directory_to_rename>
次の行に注意してください。
("\\", "_bsl_"),
pythonでは、バックスラッシュを別のバックスラッシュでエスケープする必要があります。