Batch rename files with Cyrillic filenames to Latin ones (transliterate file names)

If you have a bunch of files with Cyrillic file names, there is a chance that some old devices such as TV embedded players, car audio systems, mp3 players may not recognize them or fail to read. The quick and dirty solution is to rename these files to Latin only characters. In order to save some time I use this handy bash script. It works flawlessly on both Windows (Git Bash) and native Linux systems.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#!/bin/bash
declare -A dictionary=(
    ["Ч"]="Ch"
    ["Ш"]="Sh"
    ["Щ"]="Sht"
    ["Ю"]="Yu"
    ["Я"]="Ya"
    ["Ж"]="Zh" 
    ["А"]="A"
    ["Б"]="B"
    ["В"]="V"
    ["Г"]="G"
    ["Д"]="D"
    ["Е"]="E"
    ["З"]="Z"
    ["И"]="I"
    ["Й"]="Y"
    ["К"]="K"
    ["Л"]="L"
    ["М"]="M"
    ["Н"]="N"
    ["О"]="O"
    ["П"]="P"
    ["Р"]="R"
    ["С"]="S"
    ["Т"]="T"
    ["У"]="U"
    ["Ф"]="F"
    ["Х"]="H"
    ["Ц"]="C"
    ["Ъ"]="A"
    ["Ь"]="I"
)
 
for letter in "${!dictionary[@]}"; do
    lowercase_from=$(echo $letter | sed 's/[[:upper:]]*/\L&/')
    lowercase_to=$(echo ${dictionary[$letter]} | awk '{print tolower($0)}')
    dictionary[$lowercase_from]=$lowercase_to
done
 
function cyr2lat {
    string=$1
    for letter in "${!dictionary[@]}"; do
        string=${string//$letter/${dictionary[$letter]}}
    done
 
    echo $string;
}
 
for f in "$@"
do
    if [ ! -f "$f" ]; then
        echo "$(basename "$0") warn: this is not a regular file (skipped): $f" >&2
        continue
    fi
 
    DIR=$(dirname "$f")
    BASENAME="$(basename "$f")"
    # convert non-latin chars using my transliterate script OR uconv from the icu-devtools package
    NEWFILENAME=$(cyr2lat "$BASENAME")
     
    if [ -f "$DIR/$NEWFILENAME" ]; then
        echo "$BASENAME warn: target filename already exists (skipped): $BASENAME/$NEWFILENAME" >&2
        continue
    fi
 
    if [ "$BASENAME" != "$NEWFILENAME" ]; then
        echo "\`$f' -> \`$NEWFILENAME'"
        mv -i "$f" "$DIR/$NEWFILENAME"
    fi
done

Example usage:

1
./cyr2lat.sh ~/Music/*.mp3

 

test