Python-эквивалент find2perl - PullRequest
       18

Python-эквивалент find2perl

14 голосов
/ 25 сентября 2011

В Perl есть прекрасная маленькая утилита, которая называется find2perl , которая преобразует (весьма точно) командную строку для утилиты Unix find в сценарий Perl, который делает то же самое.

Если у вас есть команда find , подобная этой:

find /usr -xdev -type d -name '*share'

                         ^^^^^^^^^^^^  => name with shell expansion of '*share'
                 ^^^^ => Directory (not a file)
           ^^^ => Do not go to external file systems
     ^^^ => the /usr directory (could be multiple directories

Находит все каталоги, заканчивающиеся на share ниже /usr

Теперь запустите find2perl /usr -xdev -type d -name '*share', и скрипт Perl сделает то же самое.Затем вы можете изменить сценарий по своему усмотрению.

Python имеет os.walk(), который, безусловно, обладает необходимой функциональностью, рекурсивным списком каталогов, но есть большие различия.

Возьмите простой случай find . -type f -print чтобы найти и распечатать все файлы в текущем каталоге.Наивная реализация, использующая os.walk(), будет выглядеть так:

for path, dirs, files in os.walk(root):
    if files:
        for file in files:
            print os.path.join(path,file)

Однако это даст результаты, отличные от ввода find . -type f -print в оболочке.

Я также тестировал различные циклы os.walk () с:

# create pipe to 'find' with the commands with arg of 'root'
find_cmd='find %s -type f' % root
args=shlex.split(find_cmd)
p=subprocess.Popen(args,stdout=subprocess.PIPE)
out,err=p.communicate()    
out=out.rstrip()            # remove terminating \n
for line in out.splitlines()
   print line

Разница в том, что os.walk () считает ссылки как файлы;найти пропускает это.

Таким образом, правильная реализация, аналогичная file . -type f -print, становится:

for path, dirs, files in os.walk(root):
    if files:
        for file in files:
            p=os.path.join(path,file)
            if os.path.isfile(p) and not os.path.islink(p):
                 print(p)

Поскольку существуют сотни вариантов поиска основных цветов и различных побочных эффектов, проверка каждого из них занимает много времени.вариант.Поскольку find является золотым стандартом в мире POSIX для подсчета файлов в дереве, для меня важно сделать это одинаково в Python.

Так что есть эквивалент find2perl, который можетиспользоваться для Python?До сих пор я только что использовал find2perl и затем вручную переводил код Perl.Это сложно, потому что операторы тестирования файла Perl отличаются от времени, чем тесты файла Python в os.path.

Ответы [ 4 ]

4 голосов
/ 25 сентября 2011

Если вы пытаетесь переопределить все find, тогда да, ваш код станет волосатым. find довольно волосатый сам по себе.

Однако в большинстве случаев вы не пытаетесь воспроизвести полное поведение поиска; Вы выполняете гораздо более простую задачу (например, «найти все файлы, заканчивающиеся на .txt»). Если вам действительно нужно все find, просто запустите find и прочитайте вывод. Как вы говорите, это золотой стандарт; Вы могли бы просто использовать его.

Я часто пишу код, который читает пути на stdin, просто чтобы я мог сделать это:

find ...a bunch of filters... | my_python_code.py
2 голосов
/ 03 октября 2011

Есть пара наблюдений и несколько фрагментов кода, которые помогут вам на вашем пути.

Во-первых, Python может выполнять код в такой форме, как Perl:

 cat code.py | python | the rest of the pipe story...

find2perl - это умный шаблон кода, который испускает функцию Perl на основе шаблона поиска. Для этого скопируйте этот шаблон, и у вас не будет «сотен перестановок», которые вы воспринимаете.

Во-вторых, результаты find2perl не являются идеальными , так как потенциально существуют различия между версиями find, такими как GNU или BSD.

В-третьих, по умолчанию os.walk снизу вверх; find сверху вниз. Это приводит к другим результатам, если ваше базовое дерево каталогов изменяется, пока вы его повторяете.

В Python вам могут помочь два проекта: twander и dupfinder . Каждый стремится быть независимым от os, и каждый рекурсивно обращается к файловой системе, например find.

Если вы шаблонируете обычную find подобную функцию в Python, задаете os.walk для рекурсии сверху вниз, используйте glob для репликации расширения оболочки и используете некоторый код, который вы найдете в этих двух проектах, вы можете скопировать find2perl без особых затруднений.

Извините, я не смог указать на что-то готовое для ваших нужд ...

1 голос
/ 30 сентября 2011

Я написал скрипт Python для использования os.walk() для поиска и замены; это может быть полезно, прежде чем писать что-то подобное.

Заменить строки в файлах на Python

И любая замена Python для find (1) будет в значительной степени полагаться на os.stat() для проверки различных свойств файла. Например, есть флаги для find (1), которые проверяют размер файла или последнюю измененную временную метку.

1 голос
/ 30 сентября 2011

Я думаю, glob может помочь в вашей реализации этого.

...