Краткий справочник по массовому переименовыванию файлов :-)


ramok аватар

ramok - Posted on 01 Август 2007

Иногда нужно производить массовые переименования файлов. Изучая командную строку юникса когда то, меня удивило отсутствие такой приятной возможности в DOS как массовые переименовывания файлов (помню было что то типа copy *.c *.bak).

1. По первому разу я просто в vi создавал множество команд mv производящие нужные действия. Самый очевидный, и самый трудоемкий путь Ж:-)

2. Позже я начал разбираться с командной строкой юникса и мог запрограммировать массовые переименования.

for i in *.c; do
  mv $i `echo $i | sed 's/\.c$/.bak/'`
done

в sed задается то как хочется переименовать файл.

Вариант для zsh

for i (*.c) mv $i $i:r.bak

3. Как оказалось позже в поставке perl имеется простенькая утилитка rename. Первым параметром можно указать кусочек кода на perl который применяется к каждому имени файла переданные как параметры.

$ rename 's/\.c\.orig$/.c/' *.c # переименовать все *.c.orig в *.c
$ rename 'y/A-Z/a-z/' *.JPG     # имена фотографий маленькими буквами
$ rename 's/\U/\u/g' *.JPG      # тоже самое
$ rename '$_=lc' *              # тоже самое, но для всех файлов
$ rename 's/deftones-//' *.mp3  # убрать префис 'deftones-' у *.mp3
$ rename 's/^/jerk-/' *.swf     # добавить префикс 'jerk-' у *.swf
$ rename 's/ /_/g' *            # пробелы в именах файлах заменить на '_'
# перевести в большой регистр часть имени файла
$ rename -v 's/s\d.*e\d/\U$&\E/' House.M.D.s0*  
House.M.D.s03e04.rus.avi renamed as House.M.D.S03E04.rus.avi
House.M.D.s03e05.rus.avi renamed as House.M.D.S03E05.rus.avi
House.M.D.s03e06.rus.avi renamed as House.M.D.S03E06.rus.avi
House.M.D.s03e07.rus.avi renamed as House.M.D.S03E07.rus.avi

# более сложный вариант by mancubus.

rename 'tr/ /_/;$_=lc' *      # переводит все файлы в директории в
                                     # нижний регистр и заменяет " " на _

4. В zsh есть модуль zmv который как раз и занимается подобными преобразованиями.
Это довольно таки сложная в использовании команда, и думаю только zsh-гуру могут в полной мере ей пользоваться Ж:-)
Но тем не менее сами разработчики предлагают сделать пару довольно таки удобных алиасов, которые ведут себя
так же как команды copy и move в DOS.

Достаточно в ~/.zshrc прописать.

autoload zmv
alias ccp='noglob zmv -CW'
alias mmv='noglob zmv -W'

noglob перед командой обозначает что * не будет пребразован в имена файлов.

ccp *.c *.bak          # для каждого файла с расширением .c создается копия с расширением .bak
mmv **/*.jpeg **/*.jpg # переименовывает файлы .jpeg во всех вложенных директориях в .jpg
zmv -v '(* *)' '${1// /_}' # в файлах в которых есть пробелы,заменить на '_' и вывести полученые имена

Маньяки могут почитать комментарии в начале скрипта для всех возможностей.
/usr/share/zsh/**/zmv

PS отдельное спасибо товарищу mancubus за то что пнул меня дописать эту статью Ж:-)

5
Ваша оценка: Ничего Рейтинг: 5 (1 vote)

$ ls *.zip | sed  -r "s/^(.*)\.zip$/mv \1.zip _\1.rar/" | sh

Переименовать имя файла в команду переименования данного файла и вернуть это шеллу... Поразительно изящное решение

Скриптик для переименования кириллических имен файлов в руглиш:

#!/usr/bin/perl
 
@ARGV || die " Usage:
    scriptname файл1 файл2 ...
    scriptname \"имя файла\" ...
    scriptname имя\\ файла ...
    scriptname \*.mp3
    scriptname \*";
 
sub translit
{
    my $text = shift;
    $text =~ y/ абвгдеёзийклмнопрстуфхъыьэ/_abvgdeezijklmnoprstufh'y'e/;
    $text =~ y/АБВГДЕЁЗИЙКЛМНОПРСТУФХЪЫЬЭ/ABVGDEEZIJKLMNOPRSTUFH'Y'E/;
    my %mchars = ('ж'=>'zh','ц'=>'tz','ч'=>'ch','ш'=>'sh','щ'=>'sch','ю'=>'ju','я'=>'ja',
                  'Ж'=>'ZH','Ц'=>'TZ','Ч'=>'CH','Ш'=>'SH','Щ'=>'SCH','Ю'=>'JU','Я'=>'JA');
    for my $c (keys %mchars) {
        $text =~ s/$c/$mchars{$c}/g;
    }
    return $text;
}
 
while (@ARGV)
{
  rename($ARGV[0],translit($ARGV[0])) || die "Can't rename $ARGV[0] to translit($ARGV[0]): $!";
  shift;
}

ЗЫ: А еще ЕМНИП вроде был патч к convmv - добавление кодировки руглиш...

Thanks for sharing your info. I truly appreciate your efforts and I am waiting
for your next post thanks once again.

у меня utf-8 и результат не впечатлял

$ touch файл && ./z файл
$ ls -l
-rw-rw-r-- 1 ramok ramok     0 Май 31 13:35 meabauay
-rwxrwxr-x 1 ramok ramok   894 Май 31 13:41 z*

Заработало, после того как сохранил скрипт в koi-8, и добавил принудительную перекодировку имени файла в koi-8

#!/usr/bin/perl 
 
use Text::Iconv;
 
@ARGV || die " Usage:
    scriptname file1 file2 ...
    scriptname \"file name\" ...
    scriptname file\\ name ...
    scriptname \*.mp3
    scriptname \*";
 
sub translit
{
    my $text = shift;
    $text = Text::Iconv->new("","koi-8")->convert($text);
    $text =~ y/ абвгдеёзийклмнопрстуфхъыьэ/_abvgdeezijklmnoprstufh'y'e/;
    $text =~ y/АБВГДЕЁЗИЙКЛМНОПРСТУФХЪЫЬЭ/ABVGDEEZIJKLMNOPRSTUFH'Y'E/;
    my %mchars = ('ж'=>'zh','ц'=>'tz','ч'=>'ch','ш'=>'sh','щ'=>'sch','ю'=>'ju','я'=>'ja',
                  'Ж'=>'ZH','Ц'=>'TZ','Ч'=>'CH','Ш'=>'SH','Щ'=>'SCH','Ю'=>'JU','Я'=>'JA');
 
    map {$text =~ s/$_/$mchars{$_}/g} (keys %mchars);
 
    return $text;
}
 
while (@ARGV)
{
  rename($ARGV[0],translit($ARGV[0])) || die "Can't rename $ARGV[0] to translit($ARGV[0]): $!";
  shift;
}

За одно вместо for использовал map.
Спасибо!

PS
кстати линка в тему

За map - спасибо, как-то протупил ;-))
Да, скриптик писался для неUTFной раскладки... Не знаю как в случае Text::Iconv, но iconv без -c спотыкается на недопустимых символах... Так что тут надо быть осторожным ;-))
А для UTFной - нечто такое:

#!/bin/bash
IFS='|';for i in `ls -1|sed -n 'H;${x;s/\n/\|/g;p}'` ; do mv -i $i  $(echo -n $i | sed -e "s/[\:,\`\'\"\{\}]//g;s/\!\[\]\(\)\@\#\$\%\^\*\+\~\;\<\>\?]//g;s/ё/e/;s/Ё/E/;s/ж/zh/;s/Ж/ZH/;s/ц/tz/;s/Ц/TZ/;s/ч/ch/;s/Ч/CH/;s/ш/sh/g;s/Ш/SH/;s/щ/s4/;s/Щ/S4/;s/ю/ju/;s/Ю/JU/;s/я/ja/;s/Я/JA/;s/&/_and_/" | sed 'y/[абвгдезийклмнопрстуфхъыьэ АБВГДЕЗИЙКЛМНОПРСТУФХЪЫЬЭ]/[abvgdezijklmnoprstufxjyje-ABVGDEZIJKLMNOPRSTUFXJYJE]/') ; done

Ссылка вернула память - все попутал %-)) Речь не о convmv, а об iconv. Руглиш (весьма отвратненький, правда) им можно сделать примерно так:

cat sometext | iconv -f utf8 -t koi-7//TRANSLIT | tr 'a-zA-Z' 'A-Za-z'

ЗЫ: Еще способ "перекодировки" (некая альтернатива convmv): свежевышедший Midnight Commander умеет по ALT-e менять кодировку прямо на файловой панели. Устанавливаем на панелях нужные кодировки и далее F5 или F6...

Уважаемые гуру.

Зачем такие сложности? :-)

В Delphin находите нужную папку с файлами в которых полный бардак.
Выделяете все файлы "Правка" > "Выделить всё"> в окне курсором мышки становитесь на выделенное, при нажатии правой кнопки мыши появляется меню, выбираете "Перименовать", появляется окошко в котором написано "объект" и #. Вместо объекта ставите все что хотите и нажимете ОК и будет вам счастье переименованное с 1 и до......

I’m not that much of a internet reader to be honest but your sites really nice, keep it up!

I'll go ahead and bookmark your site to come back down the road.
Many thanks

Fantastic beat ! I wish to apprentice while you amend
your site, how can i subscribe for a blog website? The account aided me a acceptable
deal. I had been tiny bit acquainted of this your broadcast
provided bright clear idea

Gut gemacht!!!! +1

Да забыл, по поводу десяток и сотен, как я с ними борюсь. Я делаю так, что бы небыло бардака с десятками сотнями и так далее, я в место "объект" ставлю нужное колличество нулей и # а далее все путем :-)

Во-первых подписыватся принято с конце сообщения, а не прямо в заголовке Ж:-)
Во-вторых не совсем понятно к чему этот коментарий: к статье или к ветке коментариев о пронумеровывании файлов?
В-третьих может стоило бы реальных примеров добавить, а лучше со скриншотами (я так понимаю Delphin это какая то GUI программа).
Идеи для примеров можно брать прямо из статьи:

  • Изменить расширения файлов
  • Пронумеровать файлы
  • Перевести имена файлов в большой/малый регистры
  • Убрать префикс или суффикс у файлов
  • и так далее..
Тогда это был бы не только критический, но и полезный коментарий Ж:-)

вместо

cp ReallyVeryLongFileNameYouDontWantToTypeTwice ReallyVeryLongFileNameYouDontWantToTypeTwice.bak

пишем

cp ReallyVeryLongFileNameYouDontWantToTypeTwice{,.bak}

взято здесь

из кучи файлов с различными именами, допустим расширением *.gif требуется привести к такому виду:
image001.gif
image002.gif
...
imageNNN.gif

Хотя это очень востребовано, но ненагугливается красивое решение...

x=1; for i in *.gif ; do mv $i image$x.gif;x=$(($x+1)); done

Жаль что начальные нули не подставляет, т.е. вид:
image1.gif
image2.gif
...
image999.gif

Что потом, при сортировке, будет вразброс...

x=1000; for i in *.gif ; do mv $i image$x.gif;x=$(($x+1)); done

с помощью rename от перла

$ rename 'no strict; $_=sprintf "image%03d.gif",$i++' *.gif

на вскидку

x=1; for i in *.gif ; do mv $i image$(printf "%03d" $x).gif;x=$(($x+1)); done

Почему-то никто не написал способ для find. Однако он тоже может команды исполнять.

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

$ find . * -exec mv {} {}.bak \;

за одно переименует все что во вложенных каталогах Ж:-)

ps
* помоему лишнее?
{} вроде надо квотировать
--
Signature invent in progress 24% ##........

>за одно переименует все что во вложенных каталогах Ж:-)

Только в текущем:
-maxdepth 1

>* помоему лишнее?
+1

>{} вроде надо квотировать
ИМХО нет

добавлено:
Виноват, квотировать нужно

А я через mc копирую/переименовываю. Выделяешь нужные файлы, жмёшь F5 или F6, в источнике пишешь:
*.c
а в приемнике:
*.bak

И всё. Или, например, поменять местами имя и расширение:
*.*
\2.\1

Только метасимволы шелл галочка должна быть включена для обоих примеров. Если её выключить, то там чуть сложнее, но зато гибче. Короче F1 в помошь :)

1) Дополнение к трудоёмкому способу :

for i in *.c; do
  mv "$i" "${i%.c}.bak"
done

2) Насчёт rename из состава perl: огромное спасибо, раньше не знал, что там можно любые команды писать; использовал только s для замены :D. Кстати, с русскими буквами это не сработает. Если локаль не utf8, то можно сделать так:

rename 'use locale; tr/ /_/;$_=lc' *

Но если utf8 - не работает. Есть идеи?

3) Не совсем в тему, но тем не менее:

Для массового переименования файлов между разными кодировками есть convmv

Чтобы lc работало с русскими буквами при локали utf8, добавить

if ( $ENV{LANG}=~ /utf/i ) { use Encode; Encode::_utf8_on($_) }

В результате получается монстр:

rename 'use locale;if($ENV{LANG}=~/utf/i){use Encode;Encode::_utf8_on($_)};tr/ /_/;$_=lc' *

Причём и это не полное решение: часть сообщения об ошибке в случае невозможности переименования будет крякозябрами :(

Есть идеи? И вообще, как обеспечить работу lc с русскими буквами без таких громоздких конструкций?

а просто use utf8;?
--
Signature invent in progress 24% ##........

hello!,I like your writing very so much! share we keep up a correspondence
extra approximately your article on AOL? I need a specialist on this area to resolve my problem.
Maybe that is you! Taking a look forward to look you.

Если список файлов берется из текстового файла (cat ./spisok.txt) и имена файлов содержат пробелы, то такая схема не будет работать

В таких случаях я поступаю так:

cat spisok.txt| while read lala;                                                0:56 07-08-04  pts/1
do
cp "$lala" "$lala".new
done

Seclorum

>Если список файлов берется из текстового файла (cat ./spisok.txt) и имена файлов содержат пробелы, то такая схема не будет работать

Какая именно? ;)

о! это тема! мне как раз нужно сконвертировать диск из koi8-r в utf8 в связи с переключением системной локали на последнюю...

Спасибо ramok за капитальный труд и mancubus за идею. Господа линуксоиды, добавляйте сюда свои способы переименовывания ;)

добавлю свои 2 копейки - пакет mmv (apt-get install mmv), включает в себя утилитки mmv, mcp, mad, mln (ну, все они линки на один exeшник, но це не столь важно ;)

I know this if off topic but I'm looking into starting my own blog and was wondering
what all is required to get set up? I'm assuming having a blog like yours would cost a pretty
penny? I'm not very web savvy so I'm not 100% certain. Any recommendations or
advice would be greatly appreciated. Many thanks

Вот еще один пример для переименовании, т.е. везде убирает префикс kinopoisk.ru- из имени файлов

$ find . -print0 -type f | xargs -0 rename -v 's/kinopoisk\.ru-//'

P.S.
у меня bash и даже с

$ shopt -s globstar

подобное

$ rename 's/kinopoisk\.ru-//' **/*

работает как то не так.

Отправить комментарий

Google Friend Connect (leave a quick comment)
loading...
Содержание этого поля является приватным и не предназначено к показу.