Dir / b / s отличается в cmd.exe и командном файле - PullRequest
0 голосов
/ 20 апреля 2019

Я хочу знать, почему существует задержка между dir /b/s C:\*.* в cmd.exe и командным файлом.

Я попробовал ударный командный файл, но мне требуется около часа, чтобы показать результат, ноdis /b/s в cmd.exe быстро показать результат.

for /f "tokens=*" %%a in ('dir/b/s c:\*.*') do (
echo "%%a" 
copy "%%a" C:\windows\ )

Пожалуйста, помогите мне показать результат в пакетном файле быстро, как cmd.exe.

Ответы [ 2 ]

1 голос
/ 20 апреля 2019

Есть два элемента, которые приводят к такому поведению

  • for /f всегда извлекает все данные, которые необходимо обработать, прежде чем начинать их обрабатывать. Это означает, что for /f будет «сидеть» (не выполнять код в предложении do), пока dir работает, ожидая всех данных.
  • Когда for /f читает файл на диске, он "просто" разместит буфер, достаточно большой, чтобы загрузить его в память, загрузить файл и начать его обработку. Но когда источником данных является выполнение команды, не зная окончательного размера данных, буфер определяется и изменяется по мере необходимости при получении выходных данных команды.

Необходимость извлечения всех данных и процесс изменения размера буфера - вот что генерирует задержку.

Почему? Как пример:

  • Если я использую dir /s /b c:\windows, я получаю список из 119343 файлов, 13 МБ данных.
  • Поскольку буфер памяти, определяемый for /f, начинается с 4 КБ и увеличивается на 4 КБ при каждом заполнении, потребуется 3327 операций изменения размера.
  • Каждый раз, когда необходимо изменить размер, выделяется новый больший буфер на 4 КБ, и данные внутри старого буфера копируются в новый больший буфер. Для 13 МБ нам нужно 3327 операций изменения размера, что означает приблизительно. 21 ГБ в операциях копирования в память (копируемые данные увеличиваются при каждом изменении размера буфера). Может быть, это не так уж много, и память быстрая, но иногда (например, здесь ) все не так просто.

Если вы добавите время, необходимое для извлечения данных с диска, ко времени, необходимому для обработки выделения памяти / копирования памяти, перед началом обработки данных , у вас будет видимая задержка.

Если вам нужно убрать задержку, не используйте for /f. Лучшим вариантом (при сохранении аналогичного подхода) может быть

for /r "c:\" %%a in (*) do (
    echo "%%~fa"
)

То есть используйте рекурсивную версию команды for из указанной начальной папки.

0 голосов
/ 20 апреля 2019

Во-первых, dir/b/s c:\*.* имеет неверный синтаксис.Это работает, потому что командный процессор Windows автоматически исправляет командную строку.Правильно было бы:

dir /b /s C:\*.*

Или на 100% действительнее, короче:

dir /b /s C:\*

Или на 100% допустимо наименьшее:

dir /b /s C:\

Общий синтаксис в командной строке Windowsэто:

команда / исполняемый файл ПРОБЕЛ аргумент 1 ПРОБЕЛ" аргумент 2 " SPACE / option

Пробел между командой dir и ее первым аргументом /b не является 100% правильным синтаксисом.Как правило, нет смысла в написании кода на языке сценариев и на языке программирования, в зависимости от автоматического исправления синтаксиса приложением, интерпретирующим код.Я вижу это каждый день, когда посещаю множество веб-сайтов со старым браузером, где старый браузер не может правильно отобразить веб-страницу только из-за неправильного кода в одном из файлов веб-страницы, который хорошо отображается в последних браузерах из-за чрезмерного автоопределенияи автоматическое исправление синтаксических ошибок, вызванных людьми, пишущими файлы веб-страницы.

Выполнение команды DIR в пакетном файле медленнее из-за FOR с параметром /F и набором в «...» запускается в фоновом режиме с использованием %CompSpec% /C новый командный процесс для выполнения командной строки DIR .Все, что в конечном итоге выводится для обработки STDOUT , захватывается FOR и обрабатывается после того, как start cmd.exe завершается само.

FOR с параметром /F игнорирует все пустые строки при обработке захваченного вывода дополнительного командного процесса.Это поведение нельзя изменить с помощью параметров.

FOR с параметром /F разбивает каждую строку на подстроки (токены) с использованием обычного пробела и символа горизонтальной табуляции в качестве разделителей строк.Поведение разделения строк можно контролировать с помощью параметра delims=, при этом использование этого параметра без указания символов отключает поведение разделения строк.

FOR с параметром /F назначает указанный циклпеременная по умолчанию только первая разделенная пробелом / табуляцией подстрока.Это поведение можно контролировать с помощью опции tokens=.Использование "tokens=*" приводит к удалению всех начальных пробелов / табуляций и назначению остальной части захваченной строки указанной переменной цикла.

FOR с параметром /F игнорирует также все строки, начинающиеся сточка с запятой по умолчанию.Это поведение можно контролировать с помощью опции eol= (конец строки).

Итак, что происходит при выполнении этой командной строки:

for /f "tokens=*" %%a in ('dir/b/s c:\*.*') do ( echo "%%a")
  1. FOR запускает в фоновом режиме командный процесс, который выполняет команду DIR .
  2. DIR ищет не скрытые файлы и каталоги на диске C: и все его не скрытыеподкаталоги и выводит их имена с полным путем для обработки STDOUT фонового командного процесса, захваченного FOR .
  3. В фоновом режиме cmd.exe завершается после DIR закончено.
  4. FOR обрабатывает захваченные строки.
    • Нет пустых строк, потому что dir /B не выводит пустых строк.
    • Нет строк, начинающихся с пробелов / табуляции, поскольку dir /B /S приводит к выводу имен файлов и каталогов с полным путемначиная с привода C: в этом случае.Имя файла или каталога без полного пути может начинаться с одного или нескольких пробелов.
    • Нет строк, начинающихся с ;, также из-за dir /B /S.Имя файла или каталога может содержать точку с запятой в качестве первого символа, но не при выводе с полным путем.
  5. FOR запускает команду ECHO для каждой строки, назначенной переменной цикла a.

Лучше будет командная строка:

for /F "eol=| delims=" %%I in ('dir /B /S C:\ 2^>nul') do echo "%%I"

Эта командная строка будет работать и для DIR опция /S не используется, что приводит к выводу только имени файла / папки без пути даже для файлов / папок, начинающихся с точки с запятой или пробела. Параметр конца строки определяется вертикальной чертой, поскольку ни одно имя файла / папки не может содержать | в соответствии с документацией Именование файлов, путей и пространств имен , опубликованной Microsoft.

Рекомендуется запустить команду в окне командной строки с /? в качестве первого и единственного аргумента, чтобы отобразить справку / документацию по этой команде перед ее использованием. Попробуйте это с for /? и dir /? в окне командной строки и запустите также cmd /?, потому что этот исполняемый файл обрабатывает командный файл.

Существует исполняемый файл %SystemRoot%\System32\robocopy.exe для копирования всего дерева каталогов или устаревший исполняемый файл %SystemRoot%\System32\xcopy.exe. См. Команды Windows и SS64.com - индекс AZ командной строки Windows CMD для документации этих двух внешних команд в дополнение к запуску их в окне командной строки с /? для краткая помощь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...