В контексте {ARG_MAX} насколько надежна команда find . -exec sh -c 'exec tool "$@" extra-arg' find-sh {} +?

Вопрос или проблема

Предположим, я хочу сделать это:

find . -exec tool {} extra-arg +

Это не работает, и я знаю почему: -exec … {} + не позволяет использовать extra-arg(и) между {} и +. Ну и ладно. Похоже, я могу внедрить extra-arg, используя оболочку, вот так:

find . -exec sh -c 'exec tool "$@" extra-arg' find-sh {} +

Мой вопрос: насколько надежен этот метод? Я имею в виду в контексте {ARG_MAX} и возможной ошибки “список аргументов слишком длинный”. Я знаю, что find … -exec … {} + должен группировать имена файлов в наборы, чтобы избежать этой ошибки. На первый взгляд команда из расширения tool "$@" extra-arg должна быть короче, чем то, что выполняет find, так что если find удается избежать “списка аргументов слишком длинного”, то и exec tool … тоже его избегет; но:

  1. Я не уверен, будет ли соответствующая структура содержать tool или /полный/абсолютный/путь/к/tool, который может быть длинным и, следовательно, возможно, сделать структуру превышающей {ARG_MAX}, несмотря на усилия, приложенные find, чтобы не превышать {ARG_MAX}.

  2. Я не уверен, может ли sh добавить что-то в соответствующую структуру и, таким образом, возможно, сделать структуру превышающей {ARG_MAX}, несмотря на усилия, приложенные find, чтобы не превышать {ARG_MAX}.

Предполагая, что find хорошо справляется с избежанием “списка аргументов слишком длинного”, могу ли я предположить, что мой exec tool …, вызванный внутри оболочки, тоже избежит этой ошибки?

Разъяснение:

  • Да, я задаю вопрос о моем попытке решения, как в случае проблемы XY; но я намеренно спрашиваю о своем попытке решения, потому что хочу понять возможные недостатки. Я знаю, что могу использовать -exec tool {} extra-arg \; и избежать проблемы. Я знаю, что могу передать (предпочтительно нуль-терминированные строки) в xargs и позволить xargs справиться с {ARG_MAX}. Если мое попытка решения не надежна, и если какое-то усовершенствование может сделать ее надежной, то я заинтересован, но только если -exec … {} + останется.
  • Я знаю, что некоторые реализации find не пытаются подходить как можно ближе к {ARG_MAX}, но согласно спецификации POSIX, find не обязан оставлять место, которое мы могли бы использовать позже. У меня нет в виду какой-либо конкретной реализации find. В этом вопросе я бы оценил общие ответы или ответы, которые сравнивают множество реализаций.
  • В контексте (1) вопрос специфический для Linux. Если хороший ответ упоминает или сравнивает с другими Unix-системами, то хорошо, я не против расширить объем таким образом; но я не требую этого.
  • В контексте (2) у меня нет на уме какой-либо конкретной реализации sh.

Ответ или решение

Вопрос о надежности конструкции, предложенной вами в контексте работы с ARG_MAX, является достаточно сложным и требует всестороннего анализа.

Контекст использования ARG_MAX

Переменная окружения ARG_MAX задает максимальное количество байт, которое можно передать в одном вызове программы через командную строку. В Linux это значение варьируется, но часто составляет 2097152 байт. Когда вы работаете с find . -exec, важно понимать, что команда find оптимизирована для группировки файлов в команде, чтобы избежать ошибки "слишком длинный список аргументов". Это достигается с помощью конструкции +, что позволяет find передавать набор аргументов, указывая при этом, что в рамках одного запуска все переданные аргументы не должны превышать ARG_MAX.

Анализ вашей конструкции

Вы предложили конструкцию, которая вызывает sh -c, чтобы передать дополнительные аргументы вашему инструменту:

find . -exec sh -c 'exec tool "$@" extra-arg' find-sh {} +

1. Длина пути к tool

При использовании exec в оболочке sh в вашей команде путь к tool (имя исполняемого файла) добавляется к общему количеству байт, передаваемых как аргументы. Если find уже использует максимальное допустимое количество байт для аргументов, то добавление пути к tool может привести к ошибке "слишком длинный список аргументов". Важным является учитывать, что find не может заранее знать, нужен ли полный путь к tool или достаточно лишь его имени. Так как это может быть реализовано различными способами, некоторые реализации могут использовать короткое имя, а другие — полный путь, что увеличивает вероятность возникновения ошибки.

2. Влияние оболочки sh

Второй момент заключается в том, что sh может добавлять дополнительные данные к вызываемой конструкции, такие как переменные окружения и контекст исполнения. Например, если в оболочке заданы дополнительные переменные окружения, это также может увеличить общее число байт, что может привести к ошибке превышения ARG_MAX. Кроме того, вызов sh -c создает новый процесс, что добавляет еще одну потенциальную точку неустойчивости.

Заключение и рекомендации

При предположении о том, что find действительно делает свою работу по сгруппировке пути и не превышает ARG_MAX, вы можете считать, что ваш exec tool... может и не столкнуться с такой же ошибкой. Однако это зависит от того, как реализованы find и sh, что делает данный метод потенциально ненадежным.

Если ваш общий сценарий предполагает регулярное использование большого числа аргументов с дополнительными, рекомендуем использовать альтернативные способы:

  1. Использовать -exec с ;: Это гарантирует, что каждый вызов tool будет выполнен с отдельно взятыми аргументами, однако это подойдет только в случаях, когда производительность не является критичной.

  2. Использовать xargs: Этот инструмент способен более надежно обрабатывать массив аргументов, избегая проблем с ARG_MAX.

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

Оцените материал
?

">
Добавить комментарий

Капча загружается...