LINUX.ORG.RU

unicode & tr


0

0

Возникла необходимость переименовать кучу файлов с русскими названиями в
транслит. В ЛОР-ФАК нашел скрипт, который это делает. 
Проблема в том, что там используется tr, который, как оказалось, 
уникод не понимает (только у меня?), а у меня как раз локаль utf8. Пришлось его немного поменять:
$ cat /usr/bin/trl-u | iconv -f KOI8-R -t UTF-8
#!/bin/sh
# russian->translit
# GOST 16876-71
# locale UTF-8

shopt -s nullglob
for NAME in *
do
CNAME=$(echo $NAME | iconv -f UTF-8 -t KOI8-R)
TRS=`echo $CNAME | tr абвгдезиклмнопрстуфцы abvgdeziklmnoprstufcy` TRS=`echo $TRS | tr АБВГДЕЗИКЛМНОПРСТУФЦЫ ABVGDEZIKLMNOPRSTUFCY` TRS=${TRS//й/jj} TRS=${TRS//Й//JJ} TRS=${TRS//х/kh} TRS=${TRS//Х/KH} TRS=${TRS//ч/ch};
TRS=${TRS//Ч/CH} TRS=${TRS//ш/sh}; TRS=${TRS//Ш/SH} TRS=${TRS//ё/jo};
TRS=${TRS//Ё/JO} TRS=${TRS//ж/zh}; TRS=${TRS//Ж/ZH} TRS=${TRS//щ/shh}; TRS=${TRS//Щ/SHH} TRS=${TRS//э/eh};
TRS=${TRS//Э/EH} TRS=${TRS//ю/ju}; TRS=${TRS//Ю/JU} TRS=${TRS//я/ja}; TRS=${TRS//Я/JA} TRS=${TRS//ъ/\`};
TRS=${TRS//ъ\`} TRS=${TRS//ь/\'}; TRS=${TRS//Ь/\'}
if [[ `file -b "$NAME"` == directory ]]; then
  mv -v "$NAME" "$TRS"
  cd "$TRS"
  "$0"
  cd ..
else
  mv -v "$NAME" "$TRS"
fi
done

То есть, смысл такой - сам файл скрипта записал в koi8-r + внутри
скрипта, прежде чем скормить имя файла tr'у, преобразовываю его в
koi8-r.
Так работает.
А теперь вопрос:
действительно не существует юникодного tr? И можно ли обойтись без
таких вот лишних телодвижений?
А может, вообще все у всех работало и так - тогда почему у меня не 
работало?

П.С. Если у кого возникали проблемы со скриптом из ФАК'а в локали 
utf8, то этот вариант - рабочий.
anonymous

Ответ на: комментарий от sdio

Спасибо, попробую, так вроде прямее выглядит.

А тр, значит, с уникодом не дружит, все-таки.

anonymous
()
Ответ на: комментарий от anonymous

Отлично, так намного лучше:

$ cat /usr/bin/ru-translit
#!/bin/sh
# russian->translit
# GOST 16876-71

shopt -s nullglob
for NAME in *
do
TRS=`echo $NAME | sed y/абвгдезиклмнопрстуфцы/abvgdeziklmnoprstufcy/`;
TRS=`echo $TRS | sed y/АБВГДЕЗИКЛМНОПРСТУФЦЫ/ABVGDEZIKLMNOPRSTUFCY/`;
TRS=${TRS//й/jj} TRS=${TRS//Й//JJ} TRS=${TRS//х/kh} TRS=${TRS//Х/KH} TRS=${TRS//ч/ch};
TRS=${TRS//Ч/CH} TRS=${TRS//ш/sh}; TRS=${TRS//Ш/SH} TRS=${TRS//ё/jo};
TRS=${TRS//Ё/JO} TRS=${TRS//ж/zh}; TRS=${TRS//Ж/ZH} TRS=${TRS//щ/shh}; TRS=${TRS//Щ/SHH} TRS=${TRS//э/eh};
TRS=${TRS//Э/EH} TRS=${TRS//ю/ju}; TRS=${TRS//Ю/JU} TRS=${TRS//я/ja}; TRS=${TRS//Я/JA} TRS=${TRS//ъ/\`};
TRS=${TRS//Ъ\`} TRS=${TRS//ь/\'}; TRS=${TRS//Ь/\'}
if [[ `file -b "$NAME"` == directory ]]; then
  mv -v "$NAME" "$TRS"
  cd "$TRS"
  "$0"
  cd ..
else
  mv -v "$NAME" "$TRS"
fi
done

anonymous
()

Обратите внимание, что tr иногда спотыкается на некоторых буквах и в KOI8-R. Вам лучше использовать перл для такой задачи, там с юникодом все в порядке.

anonymous
()
Ответ на: комментарий от anonymous

Как оказалось, sed + bash вполне справляются, так что перл здесь, наверное, лишний.

Хорошо бы В фак'е поменять скрипт.

anonymous
()
Ответ на: комментарий от anonymous

Вот так, например:

#!/bin/sh
# russian->translit
# GOST 16876-71

shopt -s nullglob
for NAME in *
do
TRS=`echo $NAME | sed -e 'y/абвгдезиклмнопрстуфцы/abvgdeziklmnoprstufcy/' \
        -e 'y/АБВГДЕЗИКЛМНОПРСТУФЦЫ/ABVGDEZIKLMNOPRSTUFCY/' \
        -e 's/й/jj/' -e 's/Й/JJ/' -e 's/х/kh/' -e 's/Х/KH/' -e 's/ч/ch/' \
        -e 's/Ч/CH/' -e 's/ш/sh/' -e 's/Ш/SH/' -e 's/ё/jo/' \
        -e 's/Ё/JO/' -e 's/ж/zh/' -e 's/Ж/ZH/' -e 's/щ/shh/' -e 's/Щ/SHH/' -e 's/э/eh/' \
        -e 's/Э/EH/' -e 's/ю/ju/' -e 's/Ю/JU/' -e 's/я/ja/' -e 's/Я/JA/' \
        -e "y/ь/\'/" -e "y/Ь/\'/" -e 's/Ъ/\`/'  -e 's/ъ/\`/' `;

if [[ `file -b "$NAME"` == directory ]]; then
        if [ "$NAME" -ne "$TRS" ]; then
                mv -v "$NAME" "$TRS"
        fi
        cd "$TRS"
        "$0"
        cd ..
else
        if [ "$NAME" -ne "$TRS" ]; then
                mv -v "$NAME" "$TRS"
        fi
fi
done

anonymous
()
Ответ на: комментарий от sdio

>if [[ `file -b "$NAME"` == directory ]]; then >if [ -d "$NAME" ]; then

Тоже думал так сделать, но потом осекся, а если это только в баше есть...

anonymous
()
Ответ на: комментарий от anonymous

Окончательный вариант, заодно и воженные ifы ушли:

#!/bin/sh # russian->translit # GOST 16876-71

shopt -s nullglob for NAME in * do TRS=`echo $NAME | sed -e 'y/БВЧЗДЕЪЙЛМНОПРТУФХЖГЩ/abvgdeziklmnoprstufcy/' \ -e 'y/бвчздеъйлмнопртуфхжгщ/ABVGDEZIKLMNOPRSTUFCY/' \ -e 's/К/jj/' -e 's/к/JJ/' -e 's/И/kh/' -e 's/и/KH/' -e 's/Ю/ch/' \ -e 's/ю/CH/' -e 's/Ы/sh/' -e 's/ы/SH/' -e 's/./jo/' \ -e 's/./JO/' -e 's/Ц/zh/' -e 's/ц/ZH/' -e 's/Э/shh/' -e 's/э/SHH/' -e 's/Ь/eh/' \ -e 's/ь/EH/' -e 's/А/ju/' -e 's/а/JU/' -e 's/С/ja/' -e 's/с/JA/' \ -e "y/Ш/\'/" -e "y/ш/\'/" -e 's/я/\`/' -e 's/Я/\`/' `;

if [ "$NAME" -ne "$TRS" ]; then mv -v "$NAME" "$TRS" fi

if [ -d "$TRS" ]; then cd "$TRS" "$0" cd .. fi done

anonymous
()
Ответ на: комментарий от anonymous

Блин, промахнулся со картинкой, оно сбросило форматирование...

#!/bin/sh
# russian->translit
# GOST 16876-71

shopt -s nullglob
for NAME in *
        do
        TRS=`echo $NAME | sed -e 'y/БВЧЗДЕЪЙЛМНОПРТУФХЖГЩ/abvgdeziklmnoprstufcy/' \
                -e 'y/бвчздеъйлмнопртуфхжгщ/ABVGDEZIKLMNOPRSTUFCY/' \
                -e 's/К/jj/' -e 's/к/JJ/' -e 's/И/kh/' -e 's/и/KH/' -e 's/Ю/ch/' \
                -e 's/ю/CH/' -e 's/Ы/sh/' -e 's/ы/SH/' -e 's/./jo/' \
                -e 's/./JO/' -e 's/Ц/zh/' -e 's/ц/ZH/' -e 's/Э/shh/' -e 's/э/SHH/' -e 's/Ь/eh/' \
                -e 's/ь/EH/' -e 's/А/ju/' -e 's/а/JU/' -e 's/С/ja/' -e 's/с/JA/' \
                -e "y/Ш/\'/" -e "y/ш/\'/" -e 's/я/\`/'  -e 's/Я/\`/' `;

        if [ "$NAME" -ne "$TRS" ]; then
                mv -v "$NAME" "$TRS"
        fi

        if [ -d "$TRS" ]; then
                cd "$TRS"
                "$0"
                cd ..
        fi
done

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.