Командная строка Bash и ограничение ввода

90

Есть ли какое-то ограничение на количество символов в bash (или других оболочках) на продолжительность ввода? Если да, то каков этот лимит символов?

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

Дерек Холден
источник
2
Входной предел очень отличается от аргумента OS уровня предела (обратите внимание , что некоторые другие аргументы , чем, например, переменные окружения вещи, также применяются к этой одной). Сгенерированная команда, переданная в операционную систему, может иметь больше или меньше символов, чем команда оболочки, которая ее сгенерировала.
Чарльз Даффи

Ответы:

127

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

$ getconf ARG_MAX    # Get argument limit in bytes

Например, в Cygwin это 32000, а в различных системах BSD и Linux, которые я использую, это где-то от 131072 до 2621440.

Если вам нужно обработать список файлов, превышающих этот предел, вы можете посмотреть xargsутилиту, которая многократно вызывает программу с подмножеством аргументов, не превышающих ARG_MAX.

Чтобы ответить на ваш конкретный вопрос, да, можно попытаться запустить команду со слишком длинным списком аргументов. Оболочка выдаст ошибку с сообщением «слишком длинный список аргументов».

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

Йенс
источник
Прекрасный ответ, но хотелось бы пояснений. Если я cmd <<< "$LONG_VAR"получу конструкцию и значение LONG_VAR превысит лимит, будет ли моя команда взорвана?
Krzysztof Jabłoński
1
@ KrzysztofJabłoński Маловероятно, потому что содержимое LONG_VARпередается по стандартному вводу - и это полностью выполняется в оболочке; он не раскрывается в качестве аргумента cmd, поэтому ограничение ARG_MAX для fork () / exec () не применяется. Попробовать легко: создайте переменную с содержимым, превышающим ARG_MAX, и выполните свою команду.
Йенс
2
Вот разъяснение, для записи: для файла m4a 8 мегабайт, я сделал: blah="$(cat /home/schwager/Music/Recordings/20090420\ 131623.m4a)"; cat <<< $blah >/dev/null. Обратите внимание на отсутствие ошибок.
Mike S
3
Небольшая оговорка. Также учитываются переменные среды. sysconf manpage > Трудно использовать ARG_MAX, потому что не указано, сколько> пространства аргументов для exec (3) используется пользовательскими> переменными среды.
Геррит
3
@ user188737 Я чувствую, что это довольно серьезная оговорка в отношении ОШИБОК . Например xargsна MacOS 10.12.6 пределах , сколько он пытается поставить в один exec()к ARG_MAX - 4096. Таким образом, использование сценариев xargsможет работать до тех пор, пока однажды кто-нибудь не поместит в среду слишком много вещей. Теперь столкнуться с этим (обойти это с помощью:) xargs -s ???.
neuralmer
44

Хорошо, жители. Так что я уже довольно давно принял ограничения на длину командной строки как евангелие. Итак, что делать со своими предположениями? Естественно - проверьте их.

В моем распоряжении есть машина с Fedora 22 (имеется в виду Linux с bash4). Я создал каталог с 500 000 инодов (файлов), каждый из которых имеет длину 18 символов. Длина командной строки составляет 9 500 000 символов. Создано таким образом:

seq 1 500000 | while read digit; do
    touch $(printf "abigfilename%06d\n" $digit);
done

И отметим:

$ getconf ARG_MAX
2097152

Обратите внимание, что я могу сделать это:

$ echo * > /dev/null

Но это не удается:

$ /bin/echo * > /dev/null
bash: /bin/echo: Argument list too long

Я могу запустить цикл for:

$ for f in *; do :; done

это еще одна встроенная оболочка.

Внимательное чтение документации поARG_MAX состояниям. Максимальная длина аргумента для функций exec . Это означает: без звонка execнет ARG_MAXограничений. Это объяснило бы, почему встроенные функции оболочки не ограничиваются ARG_MAX.

И действительно, я могу использовать lsсвой каталог, если мой список аргументов содержит 109948 файлов или около 2 089 000 символов (плюс-минус). Однако как только я добавляю еще один 18-значный файл с именем файла, я получаю слишком длинный список аргументов . Итак ARG_MAX, работает так, как заявлено: exec не работает с более чем ARG_MAXсимволами в списке аргументов, включая, следует отметить, данные среды.

Майк С
источник
Хм. Я не читал существующий ответ, чтобы подразумевать, что встроенные функции подчиняются рассматриваемому ограничению, но, безусловно, могу понять, как кто-то может.
Чарльз Даффи
6
Да, я думаю, что трудно вспомнить - особенно для новых фанатов командной строки - что ситуация вызова встроенной команды bash и выполнения команды fork / exec отличается неочевидными способами. Я хотел прояснить это. Один вопрос, который я неизменно получаю на собеседовании (как системный администратор Linux): «Итак, у меня есть куча файлов в каталоге. Как мне перебрать их все ...» Спрашивающий неизменно приближается к очереди. ограничение длины и требуется решение find / while или xargs. В будущем я скажу: «черт возьми, просто используйте цикл for. Он справится с этим!» :-)
Mike S
@MikeS, в то время как вы можете выполнить цикл for, но если вы можете использовать комбинацию find-xargs, вы получите намного меньше вилки и будете быстрее. ;-)
Lester Cheung
4
@LesterCheung вообще for f in *; do echo $f; doneне будет форкнуть (все встроенные функции). Так что я не знаю, будет ли комбинация find-xargs быстрее; это не было проверено. В самом деле, я не знаю, в чем состоит проблема OP. Может быть, find /path/to/directoryон ему не пригодится, потому что вернет путь к файлу. Может, ему нравится простота for f in *петли. Тем не менее, разговор идет об ограничении линейного ввода, а не об эффективности. Итак, остановимся на теме, касающейся длины командной строки.
Mike S
FWIW, насколько я помню, проблема заключалась в том, чтобы просто написать оболочку на C и определить, как долго я должен разрешать ввод.
Derek Halden
-3

Ограничение буфера составляет примерно 1024. Чтение просто зависнет в середине вставки или ввода. Чтобы решить эту проблему, используйте параметр -e.

http://linuxcommand.org/lc3_man_pages/readh.html

-e использовать Readline для получения строки в интерактивной оболочке

Измените чтение на read -e, и надоедливое зависание строки исчезнет.

Пол Кенджора
источник
1
Речь не идет о read: «Т.е. можно ли написать в bash команду, которая слишком длинна для выполнения из командной строки?»
Чай Т. Рекс
@ ChaiT.Rex, вы вроде как правы, но вот в чем дело: попробуйте запустить Bash в интерактивном режиме без Readline, т.е. bash --noeditingв новом приглашении попробуйте запустить команду echo somereallylongword, где somereallylongword длиннее 4090 символов. При пробах на Ubuntu 18.04 слово было усечено, поэтому очевидно, что оно как-то связано с отключением Readline.
Амир
@Amir Интересно! Ты прав! Я попытался отредактировать ответ, но затем понял, что параметр -e не применяется к bash в этом контексте (в bash он немедленно выходит из оболочки при ошибке). И я не уверен, почему Пол повернулся, чтобы читать. В любом случае, при запуске bash с параметром --noreadline существует ограничение на размер буфера от 4 до 5000 символов. Это побочный эффект, о котором я не знал и не ожидал.
Mike S,