"Аргументаційний список занадто довгий": Як я з ним поводжуся, не змінюючи команди?


18

Коли я запускаю команду типу ls */*/*/*/*.jpg, я отримую помилку

-bash: /bin/ls: Argument list too long

Я знаю, чому це відбувається: це тому, що є обмеження ядра на кількість місця для аргументів команди. Стандартна порада - змінити команду, яку я використовую, щоб не вимагати стільки місця для аргументів (наприклад, використання findта xargs).

Що робити, якщо я не хочу змінювати команду? Що робити, якщо я хочу продовжувати використовувати ту саму команду? Як я можу змусити речі "просто працювати", не отримуючи цієї помилки? Які рішення доступні?


Корисне читання: Bash FAQ 95 . Без зміни команди не можна багато зробити, крім того, щоб перекомпілювати збільшити максимальний розмір списку аргументів або змінити структуру каталогу, щоб було менше файлів.
jw013

1
@ jw013 на основі версії ядра Linux можливо збільшити список аргументів - детальну інформацію про зміни в останніх системах див. у Unix.stackexchange.com/a/45161/8979 .
Ульріх Дангель

@UlrichDangel, так, це можливо! Дивіться мою відповідь; моя відповідь показує, як це зробити (в Linux, з досить недавнім ядром).
DW

Відповіді:


26

В Linux максимальна кількість місця для аргументів команди становить 1/4 від кількості доступного простору стеку. Отже, рішення - збільшити кількість місця, доступного для стека.

Коротка версія: запустіть щось на кшталт

ulimit -s 65536

Більш дрібна версія: За замовчуванням доступний простір для стека - це приблизно 8192 Кб. Ви можете переглянути кількість доступного місця таким чином:

$ ulimit -s
8192

Виберіть більшу кількість і встановіть кількість місця для стека. Наприклад, якщо ви хочете спробувати дозволити до 65536 КБ для стека, запустіть це:

$ ulimit -s 65536

Можливо, вам доведеться пограти з тим, наскільки це потрібно, використовуючи пробну помилку. У багатьох випадках це швидке і брудним рішення , яке усуне необхідність зміни команди і роботи з синтаксису find, xargsі т.д. (хоча я розумію , що є і інші переваги для цього).

Я вважаю, що це специфічно для Linux. Я підозрюю, що це, ймовірно, не допоможе в будь-якій іншій операційній системі Unix (не перевірена).


1
Ви можете перевірити так, як це працювало: $ getconf ARG_MAX 2097152 $ ulimit -s 65535 $ getconf ARG_MAX 16776960
Алекс

2

Ця стаття Linux Journal містить 4 рішення. Тільки четверте рішення не передбачає зміни команди:

Метод №4 включає вручну збільшення кількості сторінок, які виділяються в ядрі для аргументів командного рядка. Якщо ви подивитеся на файл include / linux / binfmts.h, ви знайдете наступне вгорі:

/*
 * MAX_ARG_PAGES defines the number of pages allocated for   arguments
 * and envelope for the new program. 32 should suffice, this gives
 * a maximum env+arg of 128kB w/4KB pages!
 */
#define MAX_ARG_PAGES 32

Щоб збільшити об'єм пам'яті, присвяченої аргументам командного рядка, вам просто потрібно надати значення MAX_ARG_PAGES з більшим числом. Після збереження цього редагування просто перекомпілюйте, встановіть і перезавантажте нове ядро ​​так, як це робили зазвичай.

В моїй власній тестовій системі мені вдалося вирішити всі свої проблеми, підвищивши це значення до 64. Після обширного тестування я не відчував жодної проблеми з часу перемикання. Це цілком очікувано, оскільки навіть при MAX_ARG_PAGESвстановленому рівні 64, найдовший можливий командний рядок, який я міг би створити, займав би лише 256 Кб системної пам’яті - це не дуже багато сучасних стандартів системного обладнання.

Переваги методу №4 зрозумілі. Тепер ви можете просто запустити команду, як зазвичай, і вона успішно завершується. Недоліки однаково очевидні. Якщо збільшити обсяг пам’яті, доступного в командному рядку, перевищує об’єм доступної системної пам’яті, ви можете створити атаку DOS на власну систему і призвести до її краху. Зокрема, на багатокористувацькі системи навіть невелике збільшення може мати суттєвий вплив, тому що кожному користувачеві надається додаткова пам'ять. Тому завжди ретельно перевіряйте у своєму власному середовищі, оскільки це найбезпечніший спосіб визначити, чи метод №4 є життєздатним варіантом для вас.

Я згоден, що обмеження серйозно дратує.


1

Замість цього ls */*/*/*/*.jpgспробуйте:

echo */*/*/*/*.jpg | xargs ls

xargs(1) знає, яка максимальна кількість аргументів є в системі, і розбиває її стандартний вхід для виклику зазначеного командного рядка кілька разів, не більше аргументів, ніж цей ліміт, який би він не був (ви також можете встановити його нижче, ніж максимум ОС, використовуючи цю -nопцію).

Наприклад, припустимо, обмеження становить 3 аргументи, і у вас є п'ять файлів. У цьому випадку xargsвиконується lsдвічі:

  1. ls 1.jpg 2.jpg 3.jpg
  2. ls 4.jpg 5.jpg

Часто це цілком підходить, але не завжди - наприклад, ви не можете розраховувати на ls(1) сортування всіх записів для вас належним чином, оскільки кожен окремий lsвиклик буде сортувати лише підмножину записів, наданих ним xargs.

Хоча ви можете перешкоджати ліміту, як запропонували інші, ліміт все ще буде - і одного дня ваша колекція JPG знову переросте його. Ви повинні підготувати свій сценарій (и) для вирішення нескінченного числа ...


Дякую за ідею! Це не поганий спосіб вирішення. Два застереження: 1. Це розділяється на каталоги та назви файлів, які мають пробіли у своїй назві, тому це не є ідеальною заміною. 2. Це збирається зіткнутися з тією ж проблемою Argument list too long, але echoзамість цього ls, на оболонках, де echoне вбудована команда оболонки? (Можливо, це не проблема в більшості снарядів, тому, можливо, це не має значення.)
DW

1
Так, спеціальні символи у назви файлів - це проблема. Найкраще використовувати findз -print0предикатом - і труба його вихід в xargsс -0опцією. echoє вбудованою оболонкою і не страждає від обмеження командного рядка exec(3).
Михайло Т.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.