Почему я получаю "/bin/sh: список аргументов слишком долго" при передаче цитируемых аргументов? - программирование
Подтвердить что ты не робот

Почему я получаю "/bin/sh: список аргументов слишком долго" при передаче цитируемых аргументов?

Как долго может быть командной строки, которая может быть передана в sh -c ''? (в bash и в оболочке bourne)

Предел намного ниже, чем у ОС (в случае современной Linux).

Например:

$ /bin/true $(seq 1 100000)
$ /bin/sh -c "/bin/true $(seq 1 100000)"
bash: /bin/sh: Argument list too long

И как я мог обойти эту проблему?

Обновление

Я хочу отметить, что getconf здесь не может помочь (потому что это не системный предел):

$ seq 1 100000 | wc -c
588895
$ getconf ARG_MAX
2097152

Обновление # 2

Теперь я понял, в чем дело. Это не ограничение оболочки, это системный предел, но для длины каждого аргумента, а не для всего списка arglist.

$ /bin/true $(seq 1 100000)
$ /bin/true "$(seq 1 100000)"
bash: /bin/true: Argument list too long

Спасибо, CodeGnome, для объяснения.

4b9b3361

Ответ 1

TL; DR

Один аргумент должен быть короче MAX_ARG_STRLEN.

Анализ

В соответствии с этой ссылкой:

И как дополнительный предел с 2.6.23, один аргумент не должен быть длиннее MAX_ARG_STRLEN (131072). Это может стать актуальным, если вы создаете длинный вызов типа "sh -c", сгенерированный длинными аргументами ".

Это именно "проблема", идентифицированная ОП. Хотя количество разрешенных аргументов может быть довольно большим (см. getconf ARG_MAX), когда вы передаете цитированную команду в /bin/sh, оболочка интерпретирует указанную команду как одну строку. В примере OP эта единственная строка превышает предел MAX_ARG_STRLEN, а не длину расширенного списка аргументов.

Спецификация реализации

Пределы аргумента являются специфичными для реализации. Тем не менее, эта статья журнала Linux предлагает несколько способов обойти их, включая увеличение системных ограничений. Это не может быть непосредственно применимо к ОП, но тем не менее полезно в общем случае.

Сделайте что-то еще

Проблема с OP не является реальной проблемой. Вопрос заключается в наложении произвольного ограничения, которое не решает проблему реального мира.

Вы можете обойти это достаточно легко, используя циклы. Например, при Bash 4:

for i in {1..100000}; do /bin/sh -c "/bin/true $i"; done

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

Опишите свою реальную проблему

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

Ответ 2

Я не получаю это сообщение об ошибке. Мой секрет? Одиночные кавычки:

/bin/sh -c '/bin/true $(seq 1 100000)'

Если я использую двойные кавычки, я получаю эту ошибку с каждой оболочкой:

$ /bin/sh -c "/bin/true $(seq 1 100000)"
-bash: /bin/sh: Argument list too long
$ /bin/bash -c "/bin/true $(seq 1 100000)"
-bash: /bin/bash: Argument list too long
$ /bin/ksh -c "/bin/true $(seq 1 100000)"
-bash: /bin/ksh: Argument list too long
$ /bin/zsh -c "/bin/true $(seq 1 100000)"
-bash: /bin/zsh: Argument list too long

Список аргументов расширяется в текущей оболочке, когда используются двойные кавычки, о чем свидетельствует тот факт, что Bash - это тот, который выдаёт ошибку "- bash:..." независимо от того, какая оболочка используется для запуска команда. В моей системе sh есть Dash, кстати.

Это справедливо даже для других "хост-оболочек":

$ dash
$ /bin/bash -c '/bin/true $(seq 1 100000)'
$ /bin/bash -c "/bin/true $(seq 1 100000)"
dash: /bin/bash: Argument list too long

Пациент: Доктор, мне больно, когда я это делаю ".
Доктор: Не делай этого.

Ответ 3

Уменьшите 100 000, пока вы больше не получите ошибку.

/bin/sh -c "/bin/true $(seq 1 99999)"
/bin/sh -c "/bin/true $(seq 1 99998)"

и др.

Ответ 4

Сделать файл с #!/bin/sh в качестве первой строки, а затем положить оставшуюся часть вашей команды в последующих строках?:)

Более серьезно, вы также можете читать команды из STDIN с помощью параметра -s, поэтому вы можете создать длинную командную строку и передать ее в /bin/sh -s

Ответ 5

на моей максимальной длине, полученной дихотомией

/bin/sh -c "/bin/true $(perl -e 'print"a"x131061')"

поэтому он дает 131071

но нет причин иметь длину строки; если это связано с большим количеством аргументов, вместо этого можно использовать "$ @"; например

/bin/sh -c 'command "[email protected]"' -- arg1 arg2 .. argn