Эквивалент Python для find2perl
Perl имеет прекрасную небольшую утилиту под названием find2perl, которая будет (довольно верно) перевести командную строку для утилиты Unix find
в Perl script сделать то же самое.
Если у вас есть команда 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 script, чтобы сделать то же самое. Затем вы можете изменить script на использование.
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() считает ссылки в виде файлов; find пропускает их.
Итак, правильная реализация, аналогичная 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.
Ответы
Ответ 1
Есть несколько наблюдений и несколько фрагментов кода, которые помогут вам на вашем пути.
Во-первых, Python может выполнять код в этой форме, как Perl:
cat code.py | python | the rest of the pipe story...
find2perl
- это умный шаблон кода, который испускает функцию Perl на основе шаблона find. Поэтому копируйте этот шаблон, и вы не будете иметь "сотни перестановок", которые вы воспринимаете.
Во-вторых, результаты от find2perl
не идеальны, так как существуют потенциальные различия между версиями find, такими как GNU или BSD.
В-третьих, по умолчанию os.walk
снизу вверх; find
сверху вниз. Это приводит к разным результатам, если ваше базовое дерево каталогов меняется во время его рекурсии.
В Python есть два проекта, которые могут вам помочь: twander и dupfinder. Каждый из них стремится быть независимым от os и каждый рекурсирует файловую систему, например find
.
Если вы создаете общую функцию find
в Python, установите os.walk
для повторной обработки сверху вниз, используйте glob для репликации расширения оболочки и используйте некоторый код, который вы найдете в этих двух проектах, вы можете реплицировать find2perl
без особых трудностей.
Извините, я не мог указать на что-то готовое для ваших нужд...
Ответ 2
Если вы пытаетесь переопределить все find
, то да, ваш код станет волосатым. find
довольно волосатый сам по себе.
В большинстве случаев вы не пытаетесь воспроизвести полное поведение find; вы выполняете гораздо более простую задачу (например, "находите все файлы, которые заканчиваются на .txt" ). Если вам действительно нужно все find
, просто запустите find
и прочитайте вывод. Как вы говорите, это золотой стандарт; вы могли бы просто использовать его.
Я часто пишу код, который читает пути на stdin
, поэтому я могу это сделать:
find ...a bunch of filters... | my_python_code.py
Ответ 3
Я думаю, glob может помочь в вашей реализации этого.
Ответ 4
Я написал Python script для использования os.walk()
для поиска и замены; это может быть полезно посмотреть, прежде чем писать что-то вроде этого.
Заменить строки в файлах с помощью Python
И любая замена Python для find (1) будет сильно зависеть от os.stat()
, чтобы проверить различные свойства файла. Например, есть флажки для поиска (1), которые проверяют размер файла или последнюю измененную метку времени.