Команда Windows 'dir': сортировать файлы по дате, если указан '/ s'

Цель: я хочу скопировать последний файл с определенным расширением из «исходного каталога» в «целевой каталог» с помощью пакетного файла. Последний файл может находиться в нескольких подкаталогах исходного каталога.

<этот комментарий подсказывает):

FOR /F "delims=|" %%I IN ('DIR "K:\path\tp\source\dir\*.ext" /B /S /O:D') DO SET NewestFile=%%I
copy "%NewestFile%" "C:\path\to\destination\dir"

Вы можете протестировать DIR "K:\path\tp\source\dir\*.ext" /B /S /O:D самостоятельно, чтобы убедиться, что он не выполняет сортировку.

Что я пробовал: Эта команда работает сама по себе: DIR "K:\path\tp\source\dir\*.ext" /S /B | sort но я не могу понять, как использовать ее в цикле for (пакетный файл завершается до того, как я смогу определить ошибку - даже с pause в конце).

Любые идеи?

См .: dir docs.


person alexleen    schedule 18.12.2018    source источник
comment
Почему вы используете | в качестве разделителя? Имена файлов Windows не могут содержать их, поэтому вы можете использовать "Delims=".   -  person Compo    schedule 19.12.2018
comment
@Compo Я получил это из связанного ответа. Изменение его на "delims=" или "tokens=*" не меняет результата.   -  person alexleen    schedule 19.12.2018
comment
Команда dir отсортирует файлы в каждом каталоге по дате. Он не отсортирует все файлы по дате. Для этого вам нужно будет вывести дату файла в формате ГГГГММДД с именем файла и отсортировать файл.   -  person Squashman    schedule 19.12.2018
comment
@Squashman: есть способ сделать это в чистом пакетном режиме. (Хотя возиться с реестром я бы не стал первым делом ...)   -  person Stephan    schedule 19.12.2018


Ответы (3)


Вы можете вызвать Powershell из командного файла, если хотите. Этот код можно сократить в более новых версиях Powershell.

for /F "delims=" %%G IN ('powershell "gci -rec | where { ! $_.PSIsContainer } | sort LastWriteTime | select -last 1 | Select-Object fullname"') do set NewestFile=%%G

Полный ответ:

cd /d "K:\path\to\source\dir"
for /F "delims=" %%G IN ('powershell "gci -rec *.ext | where { ! $_.PSIsContainer } | sort LastWriteTime | select -last 1 | Select-Object fullname"') do set NewestFile=%%G
copy "%NewestFile%" "C:\path\to\dest\dir"
person Squashman    schedule 19.12.2018
comment
Я отредактировал ваш ответ, включив в него полное решение - спасибо! - person alexleen; 19.12.2018
comment
@alexleen, вам может потребоваться быть очень осторожным с этим решением, я чувствую, что возвращенное имя файла может очень легко стать усеченным, и файл впоследствии не будет скопирован - person Compo; 19.12.2018
comment
Чтобы смягчить некоторые из ошибок длинного пути к файлу, вы можете использовать команду PUSHD с исходным каталогом. ROBOCOPY - единственная известная мне программа, у которой нет проблем с длинными путями к файлам. ROBOCOPY не поможет найти самый новый файл без особых манипуляций, будь то командный файл или Powershell. - person Squashman; 19.12.2018
comment
Пути не должны быть слишком длинными @Squashman, потенциальная проблема не в длине как таковой, а в возвращаемом фиксированном столбце, который усекается. - person Compo; 19.12.2018

Простое решение могло быть

@echo off
    setlocal enableextensions disabledelayedexpansion

    set "root=K:\path\tp\source\dir"
    set "mask=*.ext"

    for %%r in ("%root%\.") do for /f "tokens=2,*" %%a in ('
        robocopy "%%~fr" "%%~fr" "%mask%" /njh /njs /nc /ns /ts /s /ndl /nocopy /is /r:0 /w:0 /l
        ^| sort /r 
        ^| cmd /v /e /c"(set /p .=&echo(!.!)"
    ') do set "lastFile=%%b"

    echo Last file : "%lastFile%"

Этот код использует robocopy для создания списка файлов с префиксом отметки времени (переключатели просто не запрашивают заголовок задания, сводку задания, класс файла, размер файла, отметку времени, рекурсивный, нет списка каталогов, нет копии информации каталога, включают то же файлы, без повтора, без ожидания, не копировать, только сгенерировать список).

Этот список с префиксом временных меток (UTF yyyy/mm/dd hh:mm:ss последняя запись файла) затем сортируется в обратном порядке, чтобы получить последний файл в первой строке. Эта строка извлекается с помощью отдельного экземпляра cmd (это позволяет избежать проблемы времени, связанной с чтением for /f длинных списков данных), поэтому for /f читает только одну строку.

Поскольку строки robocopy содержат дату, время и имя файла, для получения этого последнего поля мы запрашиваем у for /f два токена: один, содержащий час (будет сохранен в %%a), и оставшийся текст до конца строки ( хранится в %%b)

Дополнительный for %%r включен только для предотвращения обычной проблемы с использованием robocopy. Поскольку мы цитируем пути, чтобы предотвратить проблемы с пробелами, нам нужно убедиться, что пути не заканчиваются обратной косой чертой, которая будет экранировать закрывающую кавычку пути и приведет к сбою команды.

person MC ND    schedule 19.12.2018

Вроде все нормально работает. Я считаю, что ваша проблема заключается в "delims=|"statement из вашей исходной функции. При использовании "delims=" все, что он будет делать, - это отрезать первый | из вывода цикла. Поскольку | не будет в обычном пути к файлу Windows, это совершенно не нужно. Попробуйте вместо этого просто добавить "tokens=*" в оператор.

Я также рекомендую использовать Set "String=" вместо традиционного Set String=, поскольку во многих случаях пробелы могут быть проблемой. Я обновил это в функции.

Пакетный скрипт:

@ECHO OFF

Rem | Configuration
Set "MainDirectory=C:\Folder1"
Set "FileExtension=*.txt"
Set "CopyDestination=C:\Folder2"

Rem | Search for the newest file in a directory/sub-directory
for /f "tokens=*" %%A in ('DIR "%MainDirectory%\%FileExtension%" /B /S /O:D') do (SET "NewestFile=%%A")

Rem | Copy file to a destination
copy "%NewestFile%" "%CopyDestination%"

goto :EOF
person John Kens    schedule 18.12.2018
comment
Это дает тот же результат. Я считаю, что проблема связана с командой dir, а не с циклом for, поскольку вы можете запустить DIR "%MainDirectory%\%FileExtension%" /B /S /O:D самостоятельно и наблюдать неправильную сортировку (или ее отсутствие). - person alexleen; 19.12.2018
comment
@alexleen У меня отлично работает на нескольких ОС. Предлагаю заглянуть в PowerShell. - person John Kens; 19.12.2018