Команда 'ls' очень медленная

У меня есть около 17k файлов в каталоге. Когда я бегу ls directoryМне нужно подождать около 15-20 секунд, прежде чем отобразятся результаты. С другой стороны, когда я бегу ls directory | wc -l или же ls directory | grep .xyz, результаты отображаются сразу.

Почему это происходит и есть ли способ это исправить?

4 ответа

Решение

Я собираюсь догадаться, что вы используете Linux.

  1. Если твой ls команда имеет псевдоним так, что она показывает файлы и папки в цвете, затем ей нужно выяснить права доступа каждого элемента (вызов stat()) и установить ли у него какие-либо "возможности файлов" (вызов getxattr()), чтобы выбрать правильный цвет. В зависимости от файловой системы эти вызовы могут быть довольно медленными, если необходимые метаданные еще не были кэшированы в ОЗУ. [Расширенные атрибуты часто находятся в области данных, поэтому каждый getxattr приводит к поиску жесткого диска.]

    С другой стороны, ls | при перенаправлении в канал автоматически отключается окраска, поэтому больше не нужно делать никаких дополнительных проверок - просто простой цикл readdir(), который возвращает имя и тип файла, и ядро, вероятно, даже реализует упреждающее чтение для этого.

  2. Обычно ls столбцы выводят, что означает, что он должен прочитать весь каталог, прежде чем он сможет что-либо выводить вообще. When run through a pipe, it automatically disables the columns mode and this buffering is no longer needed. (The total run time isn't necessarily faster, but the output begins earlier, making it feel more responsive.)

использование strace или же perf trace to check which system calls, if any, are taking a long time.

Две вещи:

  1. Если вы бежите ls первый и ls | wc -l позже возможно, что первый будет считывать с вашего жесткого диска, а второй будет считывать кэшированные данные. Если так, ls изначально "глохнет" и ничего не печатает в течение нескольких секунд. Другая ls начнет печатать почти сразу, пока кэшированные данные все еще там. Если вы начали с ls | wc -l во-первых, пришлось бы ждать, пока HDD предоставит данные.
  2. Любой терминал работает со своей скоростью. Формально stty speed покажет вам некоторую ценность, но я думаю, что это не имеет значения для виртуального терминала. Тем не менее, отображение символов и прокрутка требует времени (см. Этот вопрос). Передача тех же данных через канал происходит быстрее.

Если вам нужна более быстрая альтернатива, которая указывает только, что такое каталог, а что такое файл:

Вы можете создать простой исполняемый файл с именем или любым другим именем, которое вы предпочитаете.~/.local/binсо следующим содержанием:

      #!/usr/bin/env python3
import os
import colorama
import sys

if len(sys.argv) == 1:
    sys.argv.append(".")

dir_content = os.listdir(sys.argv[1])

for x in dir_content:
    if os.path.isdir(os.path.abspath(f"{sys.argv[1]}/{x}")):
        print(colorama.Fore.BLUE+x+colorama.Fore.RESET)
    else:
        print(x)

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

Теперь после записи вышеуказанного файла измените его режим на исполняемый:

      chmod +x ~/.local/bin/ls_fast

или как вы это назвали. Теперь перезапустите терминал, и у вас должна появиться простая команда с именемls_fastс тобой. У команды не так много функций, но она просто работает.

Думаю, на вопрос, почему это происходит, уже дан ответ. Чтобы быстро обойти проблему, используйте команду:

python -c "import os; print(os.listdir('.'))"

Это не делает всех изящных дополнительных вещей, ls просто печатает файлы на экране. Для более удобного чтения вывода вы можете использовать что-то вроде:

python -c "import os; print('\n'.join(sorted(os.listdir('.'))))"
Другие вопросы по тегам