Список аргументів занадто довгий для ls


48

Я отримую таку помилку під час спроби ls *.txt | wc -lкаталогу, який містить багато файлів:

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

Чи залежить поріг цього "списку аргументів" від дистрибутива чи специфіки комп'ютера? Зазвичай я б передав результат такого великого результату в деякі інші команди ( wc -lнаприклад), тому я не переймаюся межами терміналу.



@manatwork Так, я теж бачив ці питання. Просто цікаво, як краще використовувати або перенаправляти довгий вихід з команди більш загальним способом.

ви можете використовувати getconf ARG_MAX, щоб отримати ліміт для більшості систем на базі Unix
Prasanth

Відповіді:


49

Занадто довгий список аргументів повідомлення про помилку надходить із * з ls *.txt.

Ці обмеження є безпекою як для бінарних програм, так і для вашого ядра. На цій сторінці ви побачите більше інформації про неї, а також про те, як використовується та обчислюється.

Немає такого обмеження щодо розміру труби. Таким чином, ви можете просто написати цю команду:

find -type f -name '*.txt'  | wc -l

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

find -type f -name '*.txt' -exec echo \;  | wc -l

NB2: Мені було цікаво, як можна створити файл із новим рядком у своєму імені. Це не так важко, як тільки ви знаєте хитрість:

touch "hello
world"

1
Я трохи змінив його, щоб він працював у випадку, коли в них є назви файлів з новими рядками. Ви також можете додати a, -maxdepth 1якщо ви не збираєтесь рахувати файли у підкаталогах.
Шон Дж. Гофф

Вам це не потрібно -exec echo \;.
Мікель

@ ShawnJ.Goff Я його протестував. Там немає необхідності `echo` в поточній версії GNU знахідка
Корена

@Coren @Mikel - не всі мають GNU find. На findОС X і на системах на базі зайнятих я вважаю, що будь-яка система, що базується на BSD, показує ім'я файлу з новим рядком у ньому, що б зіпсувалося з кількістю.
Шон Дж. Гофф

Так? wc -lпідраховує нові рядки. Тож ми хочемо, щоб у нього були нові рядки.
Мікель

11

В основному це залежить від вашої версії ядра Linux.

Ви повинні мати можливість бачити ліміт для вашої системи, запустивши

getconf ARG_MAX

який повідомляє вам про максимальну кількість байтів, які може мати командний рядок після розширення оболонкою.

У Linux <2.6.23 ліміт зазвичай становить 128 КБ.

В Linux> = 2.6.25 ліміт становить або 128 КБ, або 1/4 розміру вашої стеки (див. ulimit -s), Залежно від того, що більше.

Детальну інформацію див. На головній сторінці execve (2) .


На жаль, трубопровід ls *.txtне вирішить проблему, оскільки ліміт знаходиться в операційній системі, а не в оболонці.

Оболонка розгортає *.txt, потім намагається викликати

exec("ls", "a.txt", "b.txt", ...)

і у вас стільки файлів, що відповідають, *.txtщо ви перевищуєте ліміт 128 КБ.

Вам доведеться зробити щось на кшталт

find . -maxdepth 1 -name "*.txt" | wc -l

замість цього.

(І дивіться коментарі Шона Дж. Гоффа нижче щодо імен файлів, що містять нові рядки.)


Вибачте, що не змогли отримати відповідь. Потрібна більша репутація. :( Дякую всім !!

Чи можете ви пояснити, що означає .і що -maxdepth 1означає в останньому рядку? Дякую! : D
Гільерме Саломе

2
@ GuilhermeSalomé .означає поточний каталог, -maxdepth 1це означає, що він не шукає у підкаталогах. Це покликане було відповідати тим самим файлам, що і файли *.txt.
Mikel

9

Ще одне вирішення:

ls | grep -c '\.txt$'

Незважаючи на те, що lsвиробляє більше продукції, ніж ls *.txtвиробляє (або намагається виробляти), вона не стикається з проблемою "занадто довгий аргумент", тому що ви не передаєте жодних аргументів ls. Зауважте, що це grepмає регулярний вираз, а не шаблон відповідності файлів.

Ви можете скористатися:

ls -U | grep -c '\.txt$'

(припустимо, що ваша версія lsпідтримує цю опцію). Це говорить про lsне сортування його результатів, що може заощадити і час, і пам'ять - і в цьому випадку порядок не має значення, оскільки ви просто підраховуєте файли. Ресурси, витрачені на сортування результатів, зазвичай не значні, але в цьому випадку ми вже знаємо, що у вас дуже велика кількість *.txtфайлів.

І вам слід розглянути можливість реорганізації файлів, щоб у вас не було стільки в одному каталозі. Це може бути, а може і не бути можливим.


1

MAX_ARG_PAGES представляється параметром ядра. Використання findі xargsє типовою комбінацією для подолання цієї межі, але я не впевнений, що це буде працювати wc.

Передача результатів у find . -name \*\.txtфайл та підрахунок рядків у цьому файлі повинні слугувати вирішенням.


Ви можете робити що завгодно з результатами ls's, це не вирішить. До тих пір, поки підстановочний знак * .txt буде розширено за ліміт, він не зможе перед тим, як запустити lsі генерувати будь-який вихід.
манатура

Щоправда, я оновив свою відповідь.
Брам

Краще. Але щоб зробити його заміною, lsвам слід вказати, -maxdepth 1щоб уникнути рекурсивного сканування підкаталогів.
манатура

Вибачте, що не змогли отримати відповідь. Потрібна більша репутація. :(

0

Це може бути брудно, але це працює для моїх потреб та в межах моєї компетенції. Я не думаю, що це працює дуже швидко, але це дозволило мені продовжувати свій день.

ls | grep jpg | <something>

Я отримував 90 000 довгий список jpgs і передав їх на avconv, щоб створити проміжок часу.

Раніше я використовував ls * .jpg | avconv, перш ніж я зіткнувся з цим питанням.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.