чому цикл не викликає помилку "занадто довгий аргумент"?


9

Я виявив, що це призведе до помилки "занадто довгий аргумент":

ls *.*

І це не підніме це:

for file in *.*
do
    echo $file
done

Чому?


Чи використовували ви одну і ту ж оболонку в обох експериментах? Можливо, /bin/bashпроти /bin/sh(що, можливо, посилання на тире)?
— maxschlepzig

Так, я здійснив експеримент із 10000 файлами з назвою файлів, які досить довгі. "ls *" не вдалося і "for f in *" вдалося.
— lamwaiman1988

Відповіді:


13

«Аргумент занадто довго» помилка E2BIG, піднятий execveсистемного виклику , якщо загальний розмір аргументів (плюс середовища, на деяких системах) занадто великий. execveВиклик є той , який запускає зовнішні процеси, в Зокрема , завантаження іншої виконуваний файл (є вхідний дзвінок, forkдля запуску окремого процесу, код якого до цих пір з того ж самого виконуваного файлу). forЦикл є внутрішньою конструкцією оболонки, тому він не пов'язаний з викликом execve. Команда ls *.*викликає помилку не тоді, коли глобус розгорнутий, а коли lsвикликається.

execveне вдається з помилкою, E2BIGколи загальний розмір аргументів команди перевищує ARG_MAX обмеження . За допомогою команди можна побачити значення цього обмеження у вашій системі getconf ARG_MAX. (Можливо, ви можете перейти цей ліміт, якщо у вас є достатня кількість пам'яті; зберігаючи ARG_MAXгарантії, які execveпрацюватимуть до тих пір, поки не виникне непов'язана помилка.)


і чому оболонка не мала межі?
— lamwaiman1988

1
@ gunbuster363 execveОбмеження застосовується ядром, воно встановлює обмеження, оскільки аргументи потрібно копіювати через пам'ять ядра в один момент, і користувацькі процеси не можуть дозволити запитувати довільну кількість пам'яті оболонки. Всередині оболонки немає жодних причин мати обмеження, все, що вписується у віртуальну пам'ять, добре.
— Жил 'ТАК - перестань бути злим'

5

Я припускаю, що в першому прикладі lsвиконується bashчерез системний виклик fork/ execпара, у другому - все, що працює, є внутрішнім bash.

execВиклик має межі, внутрішня обробка bashзамість не має (або краще, має різні обмеження , які не мають нічого спільного з exec, можливо , обсягом доступної пам'яті).


Ви можете знайти обмеження execв, /usr/include/linux/limits.hяк правило, визначеному як ARG_MAX.
— jw013

Якщо ми використовуємо оболонку для циклу, чи вважаєте ви, що великий список елементів буде споживати всю оперативну пам’ять?
— lamwaiman1988

Ця відповідь невірна. Це не "внутрішнє", це лише те, що межі аргументів та команд різні.
— многочлен

5

Тому що у разі lsце аргумент, а кількість аргументів обмежена.

У випадку forциклу це лише перелік елементів. Для цього немає обмежень (наскільки мені відомо).


Виразно існує обмеження для розширення оболонки. Це дуже пов'язано з тим, скільки у вас є оперативної пам’яті. Спробуйте це; моя 4 Гб оперативної пам’яті for i in {00000001..20000000} ;do ((10#$i==1)) && break; done
— пробиває

4
@fred Я не дуже вважав, що потрібно згадувати оперативну пам'ять як обмеження.
— Šimon Tóth

2
Це може не знадобитися, але така природа коментарів .. хтось може вважати це цікавим або навіть корисним.
— Пітер.O

@fred: насправді так, якщо поширення дуже великих аргументів було загальною проблемою, можна було б реалізувати це, не зберігаючи все в пам’яті.
— Маттео
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.