Вопрос или проблема
Предположим, я хочу сделать это:
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 …
тоже его избегет; но:
-
Я не уверен, будет ли соответствующая структура содержать
tool
или/полный/абсолютный/путь/к/tool
, который может быть длинным и, следовательно, возможно, сделать структуру превышающей{ARG_MAX}
, несмотря на усилия, приложенныеfind
, чтобы не превышать{ARG_MAX}
. -
Я не уверен, может ли
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
, что делает данный метод потенциально ненадежным.
Если ваш общий сценарий предполагает регулярное использование большого числа аргументов с дополнительными, рекомендуем использовать альтернативные способы:
-
Использовать
-exec
с;
: Это гарантирует, что каждый вызовtool
будет выполнен с отдельно взятыми аргументами, однако это подойдет только в случаях, когда производительность не является критичной. -
Использовать
xargs
: Этот инструмент способен более надежно обрабатывать массив аргументов, избегая проблем сARG_MAX
.
Хотя предложенный вами подход имеет свои возможные применения и может работать для определенных случаев, обращая внимание на ту ненадежность, с которой он может столкнуться, лучше рассмотреть более устойчивые методы.