пятница, 21 июля 2023 г.

CMD передать аргуметом файлы с определнной датой

Я уже и говорил в предыдущей записи почему все это началось - по работе появилась необходимость автоматизации рутинного процесса. Смысл был такой, что есть некая программа, способная выводить графики процессов агрегата за определенный период времени. Начальство требует этот график в конце каждой смены: открываешь программу, добавляешь в нее файлы за смену (несколько штук, причем количество файлов может варьироваться), добавляешь правило анализа, жмешь кнопку print, печатаешь в pdf и отправляешь этот файл по email. Если бы мастер мог сам все это делать (но у них нет желания и способностей к обучению как мне кажется), то я бы даже не заморачивался, но поскольку приходится самому, то мне стало интересно потратить 12 часов рабочего времени на автоматизацию работы, которая занимает 5 минут:

Мне очень повезло, что программа, которая используется для распечатки этих графиков, имеет возможность работы из командной строки. Она принимает в качестве аргументов пути к файлам анализа и файлам с данными, а на выходе может выдавать pdf с графиком. В таком ключе задача становится тривиальной: нужно при помощи командной строки получить пути к файлам данных и передать их в качестве аргумента. Осложняется это дело тем, что каждый файл имеет уникальное имя, и кроме того имеет дату изменения, что тоже надо учитывать, т.к.  все файлы скармливать в программу нет необходимости, и даже более того вредно, т.к. тратятся лишние ресурсы. Еще один момент - это переход из папки в папку на границе смен. Но все это решается простым методом "в лоб", за счет разбиения на более мелкие подзадачи. Однако решение мелких подзадач оказалось не самым очевидным для меня, а именно потребовало навыкы владения командной строкой, где синтаксис для меня не самый понятный, но тем не менее все получилось.

Перво наперво, нужно понять из какой папки забирать файлы, а это папка с именем текущей даты в формате yyMMDD. Как это сделать разобрались еще в прошлой заметке. Теперь можно открыть эту папку (команда cd %folder%) и получbть список файлов, который особым методом отправляется в массив:

setlocal disableDelayedExpansion
:: Load the file path "array"
for /f "tokens=1* delims=:" %%A in ('dir /s /b^|findstr /n "^"') do (
  set "file.%%A=%%B"
  set "file.count=%%A"
)

конструкция расшифровывается примерно так: если ввести просто команду dir /s /b то будет возвращен обычный список из полных имен файлов, который включает в себя и полный путь. Соответственно вся эта конструкция осуществляет поиск в это списке эти пути, и отправляет в массив file. Синтаксис до сих пор не понятен, но зато после чтения массива, можно обратиться к каждому файлу и прочитать его время и дату изменения, и если оно совпадает с тем что требуется, то добавлем его в общую строку %concat% которую позднее скормим нашей программе для вывода графиков:

:: Access the values
setlocal enableDelayedExpansion
FOR /l %%N in (1 1 %file.count%) do (
    FOR %%? IN ("!file.%%N!") DO set filedate=%%~t?
    set day=!filedate:~0,2!
    set hour=!filedate:~11,2!
    set yday=!yest:~4,2!
    if !day! EQU %date:~0,2% SET concat=!concat! "!file.%%N!"
    if !day! EQU !yday! if !hour! GTR 19 (
        SET concat=!concat! "!file.%%N!"
    echo H:!hour! y:!yday!
    )
)
Итак, первый FOR читает массив, второй FOR для каждого файла из массива отправляет в переменную %filedate% его время и дату создания. Причем опять же синтаксис маскимально непонятный - конструкция тупо скопированна из примера, например, почему именно %%~t? нужно для этого мне не понятно. Более того, как выяснилось, переменные для вывода значений за пределом массива обрамляются процентами %%, а внутри массива восклицательными знаками !! - зачем именно так, тоже странно. Как и говорилось в предыдущей заметке, знак с тильдой указывает место (начиная с нуля) и количество символов, которые будут отправляться в переменную day, hour, yday (вчерашний день).

Далее день сравнивается с текущим днем, и если они равны, то в общую строку %concat% отправляется путь до этого файла. Дополнительное условие сравнивающее время создания файла со вчерашним днем и часом создания с 19 необходимо по той причине что за ночную смену, файлы раскиданы по разным папкам, поэтому приходится делать проверки дважды, после смены папки на вчерашний день (по факту проверяется сначала вчерашний день, а затем уже день сегодняшний). Делается это при помощи меток и метода goto. После того как все нужные файлы добавлены в общую строку, ее можно отправить в качестве аргумента для запуска программы графиков:

set string="C:\Program Files\thisProgram\program.exe"%concat% C:\dat\cgl-b4.pdo /append /report:C:\dat\CGL_%date%.pdf
echo %string%
%string%

После создания скриптов для ночной смены и дневной, можно добавить их в планировщик заданий на ежедневный запуск по времени. А еще было бы круто автоматизировать отправку по почте, но то уже совсем другая история. Цельный скрипт выглядит вот так:

@echo off
SET folder=C:\datfiles\%date:~8,2%%date:~3,2%%date:~0,2%
for /f "tokens=*" %%a in ('PowerShell -Command "& {Get-Date (Get-Date).addDays(-1) -format "yyMMdd"}"') do set yest=%%a
set cycle=0
cd C:\datfiles\%yest%
:M1
setlocal disableDelayedExpansion
:: Load the file path "array"
for /f "tokens=1* delims=:" %%A in ('dir /s /b^|findstr /n "^"') do (
  set "file.%%A=%%B"
  set "file.count=%%A"
)

:: Access the values
setlocal enableDelayedExpansion
FOR /l %%N in (1 1 %file.count%) do (
    
    FOR %%? IN ("!file.%%N!") DO set filedate=%%~t?
    set day=!filedate:~0,2!
    set hour=!filedate:~11,2!
    set yday=!yest:~4,2!
    if !day! EQU %date:~0,2% SET concat=!concat! "!file.%%N!"
    if !day! EQU !yday! if !hour! GTR 19 (
        SET concat=!concat! "!file.%%N!"
    echo H:!hour! y:!yday!
    )
)

cd %folder%
set /A cycle=cycle+1
echo cnumb__%cycle%
if %cycle% LEQ 1 goto M1
set string="C:\Program Files\thisProgram\program.exe"%concat% C:\dat\cgl-b4.pdo /append /report:C:\dat\CGL_%date%.pdf
echo %string%
%string%


Комментариев нет:

Отправить комментарий