Передача очень длинного списка как sys.argv (pvpython в python)

Ошибка:

OSError: [Errno 7] Список аргументов слишком длинный

История:

Запуск скрипта на pvpython (vtk); однако в более старых дистрибутивах pvpython < 5.0 модули matplotlib устарели, поэтому использование этого модуля невозможно. Чтобы преодолеть это, другой .py используется и аргументы передаются в терминале с помощью subprocess как показано ниже и работает на Python, но так как передаваемая информация велика, вышеуказанная ошибка встречается.

Проблемный код:

import subprocess
command = ("python illustrations.py %s %s %s %s %s %s %s %s %s %s" % (str(post_processing), str(width), str(height), str(len(new_overall_lines)), str(reset_scale), str(str_rose_angle), str(str_damage), str(fname), str(fname1), str("ax=None")))
subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)

argv 6 и 7 являются чрезвычайно длинными (882770, 879326) символами каждый, поскольку они являются списками.

Альтернативным решением может быть передача списка во временный файл и загрузка его в модуль python. Но я пытаюсь сэкономить на записи и времени загрузки.

Таким образом я ищу способ передать большие аргументы в терминале или как передать аргументы двух средах, в данном случае pvpython и python.

1 ответ

Непосредственно видимая возможная причина заключается в том, что вы не используете правильное цитирование и экранирование в соответствии с синтаксисом вашей системной оболочки при создании командной строки. Поэтому, если строковое представление вашего аргумента имеет пробелы или специальные символы оболочки, оно будет неверно истолковано как много аргументов (или хуже).

Так что не используйтеshell=True (который не рекомендуется использовать специально по этой причине!) и вызвать вашу программу через правильный список аргументов:

command = ["python", "illustrations.py"] +
          [str(v) for v in post_processing, width, height,
                            len(new_overall_lines), reset_scale,
                            str_rose_angle, str_damage,
                            fname, fname1] +
          ["ax=None"]

subprocess.Popen(command, stdout=subprocess.PIPE)

Кроме того, и поскольку передача командной строки зависит от ОС (например, в Windows, ваш массив все равно будет объединен в одну строку под капотом, потому что это как CreateProcess требует передачи командной строки), а отдельные аргументы командной строки также подчиняются ограничениям длины, лучшее решение - передавать произвольно длинные данные с помощью средств, отличных от командной строки.

Существуют следующие способы передачи информации дочернему процессу:

  • Командная строка
  • файлы (поскольку файловая система является общим ресурсом, с учетом соображений защиты от других процессов)
  • IPC (каналы, включая стандартные потоки, разделяемую память, сокеты и т. Д.)
  • вещи, унаследованные через fork():
    • снимок памяти (применяется только в том случае, если ребенок запускает ту же программу)
    • дескрипторы (стандартные потоки также попадают сюда; обратите внимание, что Python намеренно помечает дескрипторы файлов, отличные от стандартных потоков, которые не наследуются по умолчанию)
    • переменные среды

Как видите, параметры командной строки далеко не единственные.

Другие вопросы по тегам