Найти - Пользователи
Полная версия: Скрипт для переименования группы файлов
Начало » Python для новичков » Скрипт для переименования группы файлов
1 2
Master_Sergius
Делаю подобие стандартной линуксовой rename, но эта стандартная не работает с регекспами.
Но есть проблемы, а точнее не переименовывает в некоторых случаях, при этом при обычном принте - всё хорошо.

Итак, код скрипта:

import re
import os
import sys
import subprocess
 
def main(cwd, pattern, rename_pattern):
    for filename in os.listdir(cwd):
        new_filename = re.sub(pattern, rename_pattern, filename)
        subprocess.call('mv %s %s' % (filename, new_filename), shell=True)
 
if __name__ == '__main__':
    cwd = os.getcwd()
    pattern = sys.argv[1]
    rename_pattern = sys.argv[2]
    main(cwd, pattern, rename_pattern)

при запуске же получаю естественно ошибки, так как надо бы екранировать пробелы, скобки и т.п. для mv команды…
Вот и есть пару вопросов: 1) может есть всё таки способ переименования группы файлов по регекспу?
2) как можно легко и безошибочно проставить руками экранирование нужных символов?
doza_and
Зачем mv? Не будет работать под windows. shutil.move, os.rename?

Переименовка по регэкспу: А чем вам find не угодил?
Master_Sergius
проставить руками экранирование
В консоли чтоли?
Master_Sergius
Я имел это ввиду:

import re
import os
import sys
import subprocess
 
ESCAPING_LIST = [' ', '(', ')']
 
def escape_symbols(string):
    for item in ESCAPING_LIST:
        string = string.replace(item, '\%s' % item)
    return string
 
def main(cwd, pattern, rename_pattern):
    for filename in os.listdir(cwd):
        new_filename = re.sub(pattern, rename_pattern, filename)
        filename = escape_symbols(filename)
        new_filename = escape_symbols(new_filename)
        #print filename, ' ',new_filename
        subprocess.call(r'mv %s %s' % (filename, new_filename), shell=True)
 
if __name__ == '__main__':
    cwd = os.getcwd()
    pattern = sys.argv[1]
    rename_pattern = sys.argv[2]
    main(cwd, pattern, rename_pattern)

Теперь всё работает )
можно создавать линку в /usr/bin )))
а не, блин, линку так просто низзя, там с путями могут быть траблы, ну, задачи такие редко встречаются, могу и копировать скриптик в папку
doza_and
получилось и ладненько. Есть еще
re.escape(string)
Сейчас не соображу он вам нужен или нет…

Думаю что использовать системный mv плохая идея.
Master_Sergius
Может быть сообразите идеальный вариант такого ренайма в целом? Да так, чтобы и линку в пользовательский каталог запихнуть? буду премного благодарен ))
Master_Sergius
Вот, пока что такой окончательный вариант, для работы в той же папке

import re
import os
import sys
 
def main(cwd, pattern, rename_pattern):
    for filename in os.listdir(cwd):
        new_filename = re.sub(pattern, rename_pattern, filename)
        filename = escape_symbols(filename)
        new_filename = escape_symbols(new_filename)
        if filename != new_filename:
            os.rename(filename, new_filename)
 
if __name__ == '__main__':
    cwd = os.getcwd()
    pattern = sys.argv[1]
    rename_pattern = sys.argv[2]
    main(cwd, pattern, rename_pattern)
py.user.next
Master_Sergius
1) может есть всё таки способ переименования группы файлов по регекспу?
rename на перле есть, ищи по Larry Wall
можно и awk применить

Master_Sergius
при запуске же получаю естественно ошибки, так как надо бы екранировать пробелы, скобки и т.п. для mv команды…
не, надо просто использовать список для вызова

Master_Sergius
2) как можно легко и безошибочно проставить руками экранирование нужных символов?
там просто не хватает одинарных кавычек вокруг каждого аргумента
doza_and
ну хорошую утилиту трудно сделать. Что вы хотите от символьных ссылок мне непонятно.
#! /bin/env/python
# -*- coding:utf-8 -*-
u""" As unix rename but regular expression syntax"""
import argparse
import shutil,os
import re
# парадигма - разработка через тестирование
def mk_fil(data):
    with open("a.dat","w") as f:
        f.write(str(data))
    return "a.dat"
def make_test_dir():
    os.renames(mk_fil(1),"aaa/a1.dat")
    os.renames(mk_fil(2),"aaa/a2.dat")
    os.renames(mk_fil(3),"aaa/bbb/a3.dat")
    os.renames(mk_fil(3),"aaa/bbb/a4.dat")
    os.renames(mk_fil(3),"aaa/bbb/4a.dat")
def test_rrename_nr():
    make_test_dir()
    try:
        rrename(ur"([a-z]+)(\d+)",ur"\2\1","aaa")
        assert(os.path.exists("aaa/1a.dat") and
           os.path.exists("aaa/2a.dat") and
           os.path.exists("aaa/bbb/a3.dat") and
           os.path.exists("aaa/bbb/a4.dat")
              )
    finally:
        shutil.rmtree("aaa")
def test_rrename_r():
    make_test_dir()
    try:
        rrename(ur"([a-z]+)(\d+)",ur"\2\1","aaa",recursive=1)
        assert(os.path.exists("aaa/1a.dat") and
           os.path.exists("aaa/2a.dat") and
           os.path.exists("aaa/bbb/3a.dat") and
           os.path.exists("aaa/bbb/4a.dat") and
           os.path.exists("aaa/bbb/a4.dat")
              )
    finally:
        shutil.rmtree("aaa")
def test_rrename_rf():
    make_test_dir()
    try:
        rrename(ur"([a-z]+)(\d+)",ur"\2\1","aaa",recursive=1,force=1)
        assert(os.path.exists("aaa/1a.dat") and
           os.path.exists("aaa/2a.dat") and
           os.path.exists("aaa/bbb/3a.dat") and
           os.path.exists("aaa/bbb/4a.dat") and
           not os.path.exists("aaa/bbb/a4.dat")
              )
    finally:
        shutil.rmtree("aaa")
# символьные ссылки лениво тестировать
# собственно код
def file_iter(root,recursive=False,symlinks=False):
    if recursive:
        for di, dl, fl in os.walk(root,followlinks=symlinks):
            for f in fl:
                yield os.path.join(di, f)
    else:
        di, dl, fl = os.walk(root).next()
        for f in fl:
            yield os.path.join(di, f)
# интерфейс для программного использования
def rrename(src,target,root=".", force=False, recursive=False, symlinks=False):
    ex = re.compile(src)
    ifail = 0
    for oldname in file_iter(root,recursive,symlinks):
        newname, n = ex.subn(target,oldname)
        if n:
            if force and os.path.exists(newname):
                os.remove(newname)
            try:
                os.rename(oldname,newname)
            except OSError:
                ifail+=1
                print "fail rename {0} -> {1}".format(oldname,newname)
    return ifail
# интерфейс для консоли
if __name__ == '__main__':
    parser = argparse.ArgumentParser(prog="rrename",description="rename files by regular expression replace")
    parser.add_argument("-r","--recursive",action='store_true',help=u"search files in subdirs")
    parser.add_argument("-f","--force",action='store_true',help=u"force file overwrite")
    parser.add_argument("-s","--symlinks",action='store_true',help=u"follow symlinks")
    parser.add_argument("-d","--directory",help=u"root directory")
    parser.add_argument("patterns",nargs="2",help=u"input_pattern output_pattern")
    args = parser.parse_args()
    root = args.directory
    if not root:
        root = "."
    sys.exit(rrename(args.patterns[0],args.patterns[1],root,args.force,args.recursive,args.symlinks))
Master_Sergius
Ох, нифига ж себе код получился! Ясно, там сразу с тестами, но ух, как страшно )

Что Я хотел от ссылок - это чтобы можно было мой скрипт запустить как обычную линуксовую утилиту, не указывая путь к запускаемому файлу, и чтобы правильно текущую директорию разбирал… Теоретически, Я догадываюсь как это сделать - линку запихнуть в один из bin каталогов, прописаных в переменной окружения PATH, а каталог передать наверное, как переменную окружения PWD.
И куда вообще желательно поместить мой скрипт?
doza_and
Master_Sergius
И куда вообще желательно поместить мой скрипт?
По уму вы должны открыть для себя setup.py http://pythonhosted.org/setuptools/setuptools.html. Пишете setup скрипт, он все правильно добавит. Логика такая - есть место где вы все разрабатываете, потом запускаете setup.py и оно копируется в нужное место вашей системы. Но вообще достаточно поместить в любое место (например /usr/bin,opt и т.п.) доступное в путях, корректно прописать первую строку и задать права на выполнение. Не спец в unix почитайте например http://proubuntu.com.ua/2011/10/27/dir.html.

Master_Sergius
нифига ж себе код получился!
Там кода 3 абзаца. И то третий потому что захотелось рекурсивное переименовывание сделать. Тест надо вынести в отдельный файл. Мне было лень границы ставить и использовать unittest поэтому я под nosetests заточил. Если оно вам надо могу кнуть окончательный вариант из 2 файлов (по уму должны еще быть setup.py и документация)
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB