Ограничен ли Python «sys.argv» максимальным количеством аргументов?

У меня есть скрипт Python, которому нужно обработать большое количество файлов. Чтобы обойти относительно небольшое ограничение Linux на количество аргументов, которые могут быть переданы команде, я использую find -print0 с xargs -0.

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

При запуске моего сценария на большом количестве файлов Python принимает только подмножество аргументов, ограничение, которое, как я сначала думал, было в argparse, но оказалось, что в sys.argv. Я не могу найти никакой документации по этому поводу. Это ошибка?

Вот пример скрипта Python, иллюстрирующий суть:

import argparse
import sys
import os

parser = argparse.ArgumentParser()
parser.add_argument('input_files', nargs='+')
args = parser.parse_args(sys.argv[1:])

print 'pid:', os.getpid(), 'argv files', len(sys.argv[1:]), 'argparse files:', len(args.input_files)

У меня есть много файлов для запуска:

$ find ~/ -name "*" -print0 | xargs -0 ls > filelist
748709 filelist

Но, похоже, xargs или Python разбивает мой большой список файлов на части и обрабатывает его несколькими разными запусками Python. :

$ find ~/ -name "*" -print0 | xargs -0 python test.py
pid: 4216 argv files 1819 number of files: 1819
pid: 4217 argv files 1845 number of files: 1845
pid: 4218 argv files 1845 number of files: 1845
pid: 4219 argv files 1845 number of files: 1845
pid: 4220 argv files 1845 number of files: 1845
pid: 4221 argv files 1845 number of files: 1845
...

Почему для обработки списка создается несколько процессов? Почему его вообще дробят? Я не думаю, что в именах файлов есть новые строки, и разве -print0 и -0 не должны решать эту проблему? Если бы были новые строки, я бы ожидал, что sed -n '1810,1830p' filelist покажет некоторую странность для приведенного выше примера. Что дает?

Я почти забыл:

$ python -V
Python 2.7.2+

person Jake Biesinger    schedule 01.02.2012    source источник
comment
Странная проблема. В качестве другого варианта вы, конечно, можете просто проанализировать filelist внутри вашего скрипта.   -  person Benjamin Bannier    schedule 02.02.2012
comment
возможный дубликат ограничений python sys.argv?   -  person jcollado    schedule 02.02.2012
comment
Это то, что делает xargs. Ему по-прежнему нужно вызывать Python через оболочку, поэтому у него будет такое же ограничение на аргументы. Почему бы не заставить вашу программу на Python принимать параметры ~/ и -name * напрямую?   -  person John La Rooy    schedule 02.02.2012
comment
Я думал, что xargs каким-то волшебным образом решает проблему ограниченного пространства аргументов. Оказывается, он просто разветвляется на отдельные процессы с меньшими фрагментами. Также оказывается, что это поведение не имеет значения в каждом приложении, для которого я использовал xargs, за исключением этого...   -  person Jake Biesinger    schedule 02.02.2012


Ответы (5)


xargs будет разделять ваши аргументы по умолчанию. Взгляните на параметры --max-args и --max-chars для xargs. Его справочная страница также объясняет ограничения (под --max-chars).

person Lars Kotthoff    schedule 01.02.2012
comment
Спасибо. Я не видел этого раньше. Есть идеи, почему приведенная выше команда find ~/ -name "*" -print0 | xargs -0 ls > filelist действительно работает? Похоже, что ls будет вызываться несколько раз, все записи (а не добавления!) в один и тот же файл. Возможно, файл открывается только один раз, и мы захватываем вывод xargs? - person Jake Biesinger; 02.02.2012
comment
Оболочка заботится о перенаправлении. ls фактически выводит на stdout. Думайте об этом как обо всем в строке внутри круглых скобок и перенаправлении снаружи. - person Lars Kotthoff; 02.02.2012

Python, кажется, не ограничивает количество аргументов, но операционная система делает это.

Посмотрите здесь для более подробного обсуждения.

person Till Hoffmann    schedule 01.02.2012

Все, что вы хотите от find, доступно от os.walk.

Не используйте find и оболочку для всего этого.

Используйте os.walk и напишите все свои правила и фильтры на Python.

«поиск времени модификации» означает, что вы будете использовать os.stat или какую-то подобную библиотечную функцию.

person S.Lott    schedule 01.02.2012
comment
В принципе я согласен с тем, что делать все это изнутри Python — это путь, используя os.walk, glob.glob и os.stat. Чего я не знал, так это того, что xargs по-прежнему подчиняется лимиту ОС и просто выполняет несколько вызовов команды с оставшимися аргументами. - person Jake Biesinger; 02.02.2012
comment
согласен в принципе значит не согласен. При этом вы не указываете причин. Вот причины, по которым ваше решение является советом. Все Python быстрее, проще и гибче. Проще, потому что это один язык: Python. Быстрее, потому что все это выполняется в одном процессе (без подкачки). Если вы хотите больше скорости, используйте multiprocessing. Наконец, он более гибкий, потому что вы не ограничены странными ограничениями find. Нет недостатка в упрощении вашего приложения. - person S.Lott; 02.02.2012
comment
Приложению обычно не требуется обрабатывать тысячи файлов. Работа обычно ведется на нескольких десятках файлов (хромосом); В конкретном тесте, который я тестирую, у меня есть тысячи файлов. Возможно, мой ОП не прояснил этого. - person Jake Biesinger; 02.02.2012
comment
@JakeBiesinger: Возможно, мой комментарий не дал понять, что find остается плохой идеей, если вы обрабатываете один файл или миллионы. Вместо того, чтобы повторять причины, я в заключение скажу, что нет никаких недостатков в замене сценария оболочки на основе find на Python. Нет недостатка. Многочисленные преимущества. - person S.Lott; 02.02.2012
comment
Конечно, есть и недостатки: вы усложняете свой сценарий дополнительной логикой. вместо того, чтобы выполнять какую-либо операцию, которую он выполнял с файлами, теперь он также имеет дело с тем, как работать с файловой системой. find невероятно мощный и уже делает это очень хорошо - person CervEd; 06.08.2021

xargs будет передавать столько, сколько сможет, но все же есть предел. Например,

find ~/ -name "*" -print0 | xargs -0 wc -l | grep total

даст вам несколько строк вывода.

Вы, вероятно, захотите, чтобы ваш сценарий либо принимал файл, содержащий список имен файлов, либо принимал имена файлов на своем стандартном вводе.

person retracile    schedule 01.02.2012

Проблема в том, что xargs ограничено количеством символов вызывающих аргументов (максимум 2091281).

Быстрый тест показал, что это диапазон от 5000 файлов до 55000 файлов, в зависимости от длины пути.

Решение, чтобы получить больше, состоит в том, чтобы вместо этого принять конвейер в пути к файлу через стандартный вход.

find ... -print0 | script.py

#!/usr/bin/env python3

import sys

files = sys.stdin.read().split('\0')
...

person CervEd    schedule 06.08.2021