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

как долго может быть командная строка, которая может быть передана в sh -c ''? (в Баш и в Борн Шелл)

предел намного ниже, чем у ОС (в случае современного 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, за объяснение.

5 ответов


TL; DR

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

анализ

по данным этой ссылке:

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

это именно "проблема", идентифицированная OP. Пока число допустимых аргументов может быть достаточно много (см. 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

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

Опишите Вашу Реальную Проблему

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


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

/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
$ /bin/bash -c '/bin/true $(seq 1 100000)'
$ /bin/bash -c "/bin/true $(seq 1 100000)"
dash: /bin/bash: Argument list too long

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


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

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

etc.


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

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


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

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

так это дает 131071

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

/bin/sh -c 'command "$@"' -- arg1 arg2 .. argn