Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   [решено] параметры цикла for для построчного анализа текстового файла?! (http://forum.oszone.net/showthread.php?t=99874)

akrav 04-02-2008 15:52 732644

параметры цикла for для построчного анализа текстового файла?!
 
Добрый день!
Есть необходимость построчно проанализировать содержимое текстового файла. Никак не могу определиться с синтаксисом.
@for /f "tokens=*" %%A in (c:\text.txt) do @echo %%A – не работает

Petya V4sechkin 04-02-2008 22:14 732949

@for /f "delims=" %%A in (c:\text.txt) do @echo %%A

Ingolder 08-08-2010 23:46 1469645

Petya V4sechkin, я так написал точьвточь - ничего не выдаёт.
как быть? мне тоже надо.

Petya V4sechkin 09-08-2010 11:51 1469913

Ingolder, не стесняйтесь подробнее описывать проблему.

Ingolder 09-08-2010 21:41 1470311

пишу в батнике:

@for /f "tokens=*" %%A in (c:\text.txt) do @echo %%A

не выводит вообще ничего.
куда ж уж подробнее?.

p.s. пишу:
@for /f "delims=" %%A in (c:\text.txt) do @echo %%A

ничего не выводит

deepred 09-08-2010 22:36 1470346

Ingolder,

А конкретнее? Что происходит, неужели совсем ничего? Это возможно только если файл tex.txt пуст...Если это единственная строка в *.bat, то добавьте после неё "pause"

gora 10-08-2010 08:31 1470549

Цитата:

Цитата deepred
Это возможно только если файл tex.txt пуст »

А также, если файл c:\text.txt отсутствует по указанному пути или он содержит спец. символы, которые батник не может "разобрать". Приведите здесь свой text.txt.

deepred 10-08-2010 09:06 1470558

Цитата:

Цитата gora
если файл c:\text.txt отсутствует по указанному пути или он содержит спец. символы, которые батник не может "разобрать" »

в данном случае было бы выдано сообщение об ошибке...
Цитата:

Цитата gora
Приведите здесь свой text.txt »

- действительно не помешало бы, а заодно и код пакетника, если таковой имеется...

NiOl 10-08-2010 12:09 1470676

1. Проверить кодировку файла
2. можно попробовать объединить: "tokens=* delims="
3. а еще перед циклом добавить setlocal enableextensions

Ingolder 11-08-2010 09:33 1471249

спасибо помогло "tokens=* delims="

gora 11-08-2010 14:10 1471426

Цитата:

Цитата Ingolder
спасибо помогло "tokens=* delims=" »

Ingolder, проявите уважение к пользователям, желавшим Вам помочь и
Цитата:

Цитата gora
Приведите здесь свой text.txt. »

Для меня, например, так и осталось загадкой почему у Вас не сработали другие предложенные варианты и что же в Вашем файле такого особенного, что они не сработали!? :dont-know

sur 28-02-2011 16:13 1623765

запиши одной строкой
@for /f "tokens=*" %%A in (c:\text.txt) do @echo %%A

Burning Hell 25-07-2017 13:36 2753896

Всем добрый день.

Пытаюсь считать содержимое текстового файла, чтобы проверить наличие внутри него отдельных ключевых слов. Проблема в том, что в имени файла находится пробел. Пробовал брать путь вместе с именем файла в двойные кавычки, но тогда это воспринимается просто как строка. Без кавычек режет до пробела. Подскажите как быть, я новичок в cmd.

Вот код:

Код:

for /f "tokens=*" %%A in ("D:\InforSec\scripts\read_log\text_test_log tst.txt") do @echo %%A
Та же проблема с параметром команды find. Вот такой вариант не работает, хотя файл есть и в нем есть слово "error":

Код:

find /I D:\InforSec\scripts\read_log\text_test_log tst.txt "error"

megaloman 25-07-2017 15:11 2753928

Код:

FOR /F "usebackq delims=" %%s IN ("D:\InforSec\scripts\read_log\text_test_log tst.txt") DO echo %%s
find /I "error" "D:\InforSec\scripts\read_log\text_test_log tst.txt" >nul &&Echo Error ||Echo Not Error


alpap 25-07-2017 15:24 2753930

Цитата:

Цитата Burning Hell
хотя файл есть и в нем есть слово "error": »

никто же не мешает проверить
Код:

@echo off
set "spath=D:\InforSec\scripts\read_log\text_test_log tst.txt"
set "sp=error"
if exist "%spath%" <"%spath%" >nul find /I "%sp%" && echo Действительно в файле "%spath%" есть искомое слово "%sp%" || echo Возможно проблемы с кодировкой файла
pause


Burning Hell 26-07-2017 14:22 2754154

Возник еще вот какой вопрос.

Мне нужно проверить наличие в файле нескольких ключевых слов. Сейчас использую один цикл for для поиска одного слова (код ниже).

Код:

for /f %%s in ('find /I "error" "%full_log_path%"') do (
        if %%s equ "error" (
        set flag=true) else (
        set flag=false)
)

Т.е., для поиска трех слов я пишу три таких цикла подряд.

Можно ли как-то оптимизировать это, т.е. проверить наличие в файле нескольких слов, используя вложенный цикл for или еще каким-либо образом?

Iska 26-07-2017 14:34 2754157

Цитата:

Цитата Burning Hell
или еще каким-либо образом? »

Или ещё.
Код:

type "%full_log_path%" | >nul 2>&1 findstr.exe /i /l /c:"word1" /c:"word2" /c:"word3" && echo Found || echo Not found

Burning Hell 26-07-2017 14:45 2754159

Iska, а включить это в условие можно как-нибудь? Если слова найдены, то соответствующий флаг = true, иначе = false

И вопрос по самому коду: что делает вот этот кусок кода:

Код:

>nul 2>&1
Понимаю, что он что-то куда-то перенаправляет (в частности, куда-то перенаправляется поток ошибок), но не совсем понимаю, что и куда.

Iska 26-07-2017 15:10 2754167

Цитата:

Цитата Burning Hell
Iska, а включить это в условие можно как-нибудь? Если слова найдены, то соответствующий флаг = true, иначе = false »

Код:

type "%full_log_path%" | >nul 2>&1 findstr.exe /i /l /c:"word1" /c:"word2" /c:"word3" && set flag=true || set flag=false
Цитата:

Цитата Burning Hell
что делает вот этот кусок кода: »

перенаправляет стандартный поток вывода (stdin, имеет номер 1, может не указываться) команды findstr.exe в пустое устройство (nul) и перенаправляет стандартный поток ошибок (stderr, имеет номер 2) в стандартный поток вывода (то есть, в данном случае, фактически, тоже в nul).

Burning Hell 26-07-2017 15:39 2754172

Iska, еще один сложный для меня момент хотел спросить.

У меня есть скрипт (код), в котором я хочу найти несколько фраз и вырезать из этих фраз подстроки.
Т.е., в коде есть строчка: lasr_port = 2289. Как мне вырезать в переменную номер порта, если номер этой строчки в исходном файле может меняться?

Iska 26-07-2017 15:49 2754176

Цитата:

Цитата Burning Hell
У меня есть скрипт (код), »

Покажите образец этого «скрипт (код)».

Цитата:

Цитата Burning Hell
в котором я хочу найти несколько фраз »

Каких? Перечислите.

Цитата:

Цитата Burning Hell
и вырезать из этих фраз подстроки. »

По какому принципу подстроки должны определяться внутри строки?

Burning Hell 26-07-2017 15:56 2754177

Цитата:

Цитата Iska
Покажите образец этого «скрипт (код)». »

Скрипт написан на SAS/Macro. Выглядит примерно так:
Код:

%global vaRepLib vaRepLib lasr_port lasr_engine lasr_tag lasr_host lasr_signer lasr_options metaport metaprotocol metarepository lasr_sig_files_path;
                       
%let vaRepLib = lasrlib;
%let lasr_port = 2289;
%let lasr_engine = sasiola;
%let lasr_tag = va_pub;
%let lasr_host = sas-vaar.dev.rnw;
%let lasr_signer = %str("http://sas-metadata.dev.rnw:85/SASLASRAuthorization");
%let lasr_options = %str(tag=&lasr_tag port=&lasr_port host="&lasr_host" signer=&lasr_signer);

Цитата:

Цитата Iska
Каких? Перечислите. »

Хотелось бы найти строчку с переменной lasr_port и вырезать в переменную число после знака "=". То же самое с переменной
lasr_host.

Iska 26-07-2017 16:22 2754181

Цитата:

Цитата Burning Hell
Скрипт написан на SAS/Macro. Выглядит примерно так: »

На всякий случай — кодировка его какая?

Цитата:

Цитата Burning Hell
Хотелось бы найти строчку с переменной lasr_port и вырезать в переменную число после знака "=". То же самое с переменной
lasr_host. »

Скрытый текст
Код:

@echo off
setlocal enableextensions enabledelayedexpansion

set sSourceFile=C:\Мои проекты\0102\0001.txt

if exist "%sSourceFile%" (
        for /f "usebackq tokens=2,3 delims==; " %%i in (
                `type "%sSourceFile%" ^| findstr.exe /i /r /c:"%%let lasr_port = [0-9]*;"`
        ) do set s%%i=%%j

        if defined slasr_port (
                echo [!slasr_port!]
        ) else (
                echo Not found [lasr_port]
        )

        for /f "usebackq tokens=2,3 delims==; " %%i in (
                `type "%sSourceFile%" ^| findstr.exe /i /r /c:"%%let lasr_host = .*;"`
        ) do set s%%i=%%j

        if defined slasr_host (
                echo [!slasr_host!]
        ) else (
                echo Not found [slasr_host]
        )

) else (
        echo Can't find source file [%sSourceFile%].
        exit /b 1
)

endlocal
exit /b 0


Burning Hell 26-07-2017 16:28 2754186

Цитата:

Цитата Iska
На всякий случай — кодировка его какая? »

UTF-8 w/o BOM

Iska 26-07-2017 16:41 2754192

Цитата:

Цитата Burning Hell
UTF-8 w/o BOM »

Тогда сойдёт (пока кириллицу из файла получать не понадобится :)).

Burning Hell 26-07-2017 16:45 2754193

Iska, возникло несколько вопросов.

Что означает вот этот оператор
Цитата:

Цитата Iska
set s%%i=%%j »

?

Для чего нужны квадратные скобки
Цитата:

Цитата Iska
[!slasr_host!] »

и что такое slasr_port? Откуда он берется?

Также я не очень понял, что делают вот эти два параметра после setlocal:

Цитата:

Цитата Iska
setlocal enableextensions enabledelayedexpansion »

Цитата:

Цитата Iska
Тогда сойдёт (пока кириллицу из файла получать не понадобится ). »

Там кириллицы по определению не может быть, это же код, исполняемый файл)

Iska 26-07-2017 17:05 2754199

Цитата:

Цитата Burning Hell
Что означает вот этот оператор »

Цитата:

Цитата Burning Hell
что такое slasr_port? Откуда он берется? »

Строка в файле выглядит как:
Код:

%let lasr_port = 2289;
Посредством цикла разбора for /f "usebackq tokens=2,3 delims==; " мы разбиваем её на составляющие:
Код:

%let lasr_port = 2289;
и выбираем второй и третий токены в %%i и %%j соответственно. Таким образом строка:
Код:

set s%%i=%%j
выполняется как:
Код:

set slasr_port=2289
s я просто добавляю как префикс для получаемой переменной окружения. Привычка.

Цитата:

Цитата Burning Hell
Для чего нужны квадратные скобки »

Для правильного восприятия. Например, чтобы визуально видеть обрамляющие пробелы, которые без ограничителей [] будут не видны.

Burning Hell 26-07-2017 17:16 2754200

Iska, правильно я понял, что
Цитата:

Цитата Iska
.* »

последовательность любых символов ?

Iska 26-07-2017 17:22 2754202

Burning Hell, правильно. В том числе и пустая последовательность. К сожалению, реализация регулярок у findstr.exe весьма куцая.

megaloman 26-07-2017 17:22 2754203

Как вариант (если после равно в строке всякие спкцсимволы - не годится)
Код:

@Echo Off
cls

Set "FileIn=Z:\Box_In\In File.txt"
Set "Key=let"

FOR /F "usebackq tokens=1,2,3 delims==; " %%i IN (`more "%FileIn%" 2^>nul`) DO (
        Call :Ident "lasr_port" "%%i" "%%j" "%%k"
        Call :Ident "lasr_host" "%%i" "%%j" "%%k"

rem Остальные три строки вставил как пример возможности
        Call :Ident "vaRepLib" "%%i" "%%j" "%%k"
        Call :Ident "lasr_engine" "%%i" "%%j" "%%k"
        Call :Ident "lasr_tag" "%%i" "%%j" "%%k"

)
Echo %lasr_port%
Echo %lasr_host%

Echo %vaRepLib%
Echo %lasr_engine%
Echo %lasr_tag%

pause
GoTo :Eof

:Ident
        If /I %2=="%Key%" If /I %1==%3 Set "%~1=%~4"
GoTo :Eof


Burning Hell 27-07-2017 09:14 2754336

Iska, подскажите пожалуйста еще пару моментов..

Что такое
Цитата:

Цитата Iska
^| »

в команде type?


Цитата:

Цитата Burning Hell
Также я не очень понял, что делают вот эти два параметра после setlocal:
Цитата Iska:
setlocal enableextensions enabledelayedexpansion » »



Еще такой вопрос...Код, который ищет lasr_port и lasr_host я положил в отдельный батник (например, 2.bat) и хочу его вызвать из основного батника (например, 1.bat) с соответствующими параметрами. Пишу так:

Код:

call 2.bat lasr_port lasr_host
В самом коде 2.bat я планирую вместо lasr_port и lasr_host использовать %1 и %2, но я не знаю как изменить вот эту строчку:

Код:

) do set s%%i=%%j
***

Можно ли как-то передать найденное значение 2289 (lasr_port) в батник 1.bat?

megaloman 27-07-2017 20:08 2754490

Burning Hell, 1.bat
Код:

@Echo Off
cls

Set "FileIn=Z:\Box_In\In File.txt"
Set Arg="lasr_port" "lasr_host"

Call Z:\я170727-2.bat "%FileIn%" "%Arg%"

Echo %lasr_port%
Echo %lasr_host%

Pause
GoTo :Eof

я170727-2.bat - придумайте своё имя, пропишите его в предыдущем батнике
Код:

Set "Key=let"
FOR /F "usebackq tokens=1,2,3 delims==; " %%i IN (`more %1 2^>nul`) DO (
        For %%a In (%~2) Do Call :Ident %%a "%%i" "%%j" "%%k"
)
GoTo :Eof

:Ident
        If /I %2=="%Key%" If /I %1==%3 Set "%~1=%~4"
GoTo :Eof


Iska 27-07-2017 20:23 2754492

Цитата:

Цитата Burning Hell
Что такое
Цитата Iska:
^| »
в команде type? »

Не так. «|» — символ конвейера между одной командой и другой. В данном случае — между type и findstr.exe. Поскольку команды находятся внутри параметра «команда» цикла разбора for /f, символ конвейера должен быть экранирован символом «^» (иначе он будет применён не к type и findstr.exe, а к for /f).

Цитата:

Цитата Burning Hell
Код, который ищет lasr_port и lasr_host я положил в отдельный батник (например, 2.bat) »

Будет проще, если Вы вместо вызова отдельного пакетного файла используете процедуры в том же пакетном файле.

Burning Hell 27-07-2017 21:00 2754502

Цитата:

Цитата Iska
Будет проще, если Вы вместо вызова отдельного пакетного файла используете процедуры в том же пакетном файле. »

Ага, я уже это понял) Поэтому код поиска lasr_port и lasr_host сделал процедурой в том же пакетном файле. И она мне возвращает эти два параметра обратно в батник, чтобы дальше их использовать.

Вопрос у меня вот какой...Можно ли перейти по метке из конца батника в его начало и заново повторить шаги? Код сейчас выглядит примерно так:

Код:

:start

....код.....
....код.....
<вызов процедуры поиска lasr_port и lasr_host>
<запуск стороннего скрипта, который формирует лог, где предполагается искать ошибку>
....код.....
....код.....

if (здесь идет некая проверка на ошибку){
<запуск стороннего скрипта, если ошибка найдена>
goto start <вернуться в начало, сгенерировать новый лог и еще раз проверить наличие в нем ошибки>
} else {
goto :EOF <закончить работу, если ошибки в последнем сгенерированном логе нет>
}

<процедура поиска lasr_port и lasr_host>

Сейчас скрипт почему-то не переходит по метке start, останавливается внутри if'a. Можно ли как-то решить эту проблему? Может быть, новую сессию открыть?

Burning Hell 27-07-2017 21:17 2754507

Цитата:

Цитата megaloman
Set "Key=let" FOR /F "usebackq tokens=1,2,3 delims==; " %%i IN (`more %1 2^>nul`) DO ( For %%a In (%~2) Do Call :Ident %%a "%%i" "%%j" "%%k" ) GoTo :Eof :Ident If /I %2=="%Key%" If /I %1==%3 Set "%~1=%~4" GoTo :Eof »

Прокомментируйте пожалуйста ваш код...Много непонятного, я модифицировал вариант Iska (возвращаю параметры в
Код:

endlocal & set /a %3=%slasr_port% & %4=%lasr_host%
), но мне интересно, как работает ваш вариант.

Iska 27-07-2017 22:32 2754524

Цитата:

Цитата Burning Hell
Можно ли перейти по метке из конца батника в его начало и заново повторить шаги? »

Перейти — можно. Вопрос — нужно ли.

Цитата:

Цитата Burning Hell
Код сейчас выглядит примерно так: »

Показывайте весь код целиком. И желательно не использовать в качестве имён переменных и меток имена внутренних команд и внешних утилит.

Burning Hell 28-07-2017 08:25 2754564

Вложений: 1
Iska, код приложил.

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

Iska 28-07-2017 08:45 2754569

Цитата:

Цитата Burning Hell
Iska, код приложил. »

В данном случае лучше делать сие так:

Скрытый текст
Код:

:start
set day=%date:~0,2%
set month=%date:~3,2%
set year=%date:~6,4%

set /a hour=%time:~0,2%
if %hour% lss 12 (
        set format=AM) else (
        set format=PM)

If %hour% gtr 12 ( set /a hour = %hour% - 12 )
If %hour% == 00 ( set hour = 12 )

set /a minute=%time:~3,2%
set /a second=%time:~6,2%

set lasr_log_nm=check_va_lasr_status_%year%-%month%-%day%__%hour%.%minute%.%second% %format%.log

set full_log_path=D:\logs\%lasr_log_nm%

call D:\SAS\sas.exe -sysin D:\codes\check_va_lasr\check_va_lasr_status.sas -log "%full_log_path%"

set port=lasr_port
set host=lasr_host

call :get_params_from_main_config %port% %host% port host

type "%full_log_path%" | >nul 2>&1 findstr.exe /i /l /c:"error" /c:"connection" /c:"lasr" /c:"%port%" /c:"%host%" && set lasrError=true || set lasrError=false

echo lasrError=%lasrError%

if %lasrError%==true (
        call D:\SAS\sas.exe -sysin D:\codes\check_va_lasr\check_lasr_log_and_run.sas -nolog
        echo "Goto second iteration"
        goto :start
) else (
goto :EOF
)

rem =========================================================================
:get_params_from_main_config
@echo off
setlocal enableextensions enabledelayedexpansion

set sSourceFile=D:\codes\common\init_environment.sas

if exist "%sSourceFile%" (
        for /f "usebackq tokens=2,3 delims==; " %%i in (
                `type "%sSourceFile%" ^| findstr.exe /i /r /c:"%%let %1 = [0-9]*;"`
        ) do set s%1=%%j

        if defined slasr_port (
                echo [!slasr_port!]
        ) else (
                echo Not found [lasr_port]
        )

        for /f "usebackq tokens=2,3 delims==; " %%i in (
                `type "%sSourceFile%" ^| findstr.exe /i /r /c:"%%let %2 = .*;"`
        ) do set s%2=%%j

        if defined slasr_host (
                echo [!slasr_host!]
        ) else (
                echo Not found [slasr_host]
        )

) else (
        echo Can't find source file [%sSourceFile%].
        exit /b 1
)

endlocal & (set /a %3=%slasr_port% & set %4=%slasr_host%)
exit /b 0
rem =========================================================================


Burning Hell 28-07-2017 09:37 2754580

Iska, но я не вижу никакой разницы...

megaloman 28-07-2017 11:15 2754599

Burning Hell,
Цитата:

Цитата Burning Hell
но я не вижу никакой разницы... »

Я не сильно всматривался, но очевидное отличие в двоеточии goto :start
Вот Ваш код с поправками Iska (я не вчитывался сильно в код и, естественно, не могу его полноценно тестировать) с встроенной моей процедурой
Код:

@Echo Off
cls

:start
set day=%date:~0,2%
set month=%date:~3,2%
set year=%date:~6,4%

set /a hour=%time:~0,2%
if %hour% lss 12 (
        set format=AM) else (
        set format=PM)

If %hour% gtr 12 ( set /a hour = %hour% - 12 )
If %hour% == 00 ( set hour = 12 )

set /a minute=%time:~3,2%
set /a second=%time:~6,2%

set lasr_log_nm=check_va_lasr_status_%year%-%month%-%day%__%hour%.%minute%.%second% %format%.log

set full_log_path=D:\logs\%lasr_log_nm%

call D:\SAS\sas.exe -sysin D:\codes\check_va_lasr\check_va_lasr_status.sas -log "%full_log_path%"

rem set port=lasr_port
rem set host=lasr_host
rem call :get_params_from_main_config %port% %host% port host
rem type "%full_log_path%" | >nul 2>&1 findstr.exe /i /l /c:"error" /c:"connection" /c:"lasr" /c:"%port%" /c:"%host%" && set lasrError=true || set lasrError=false

Call :get_params_from_main_config "D:\codes\common\init_environment.sas" ""lasr_port" "lasr_host""
type "%full_log_path%" | >nul 2>&1 findstr.exe /i /l /c:"error" /c:"connection" /c:"lasr" /c:"%lasr_port%" /c:"%lasr_host%" && set

lasrError=true || set lasrError=false

echo lasrError=%lasrError%

if %lasrError%==true (
        call D:\SAS\sas.exe -sysin D:\codes\check_va_lasr\check_lasr_log_and_run.sas -nolog
        echo "Goto second iteration"
        goto :start
) else (
        goto :EOF
)

rem =========================================================================

:get_params_from_main_config
        Set "Key=let"
        FOR /F "usebackq tokens=1,2,3 delims==; " %%i IN (`more %1 2^>nul`) DO (
                For %%a In (%~2) Do Call :Ident %%a "%%i" "%%j" "%%k"
        )
GoTo :Eof

:Ident
        If /I %2=="%Key%" If /I %1==%3 Set "%~1=%~4"
GoTo :Eof

Аналогичная процедура от Iska убрана
Попробую в темпе пояснить мою процедуру
Код:

Call :get_params_from_main_config "D:\codes\common\init_environment.sas" ""lasr_port" "lasr_host""
Вызов Call :get_params_from_main_config "Имя анализируемого файла" "Список искомых параметров"
Список искомых параметров в виде ""Парам1" "Парам2" ..."ПарамN""
После работы процедуры получим переменные, которым присвоены найденные (если они есть) значения
%Парам1% %Парам2% ... %ПарамN%

Под первым For команда (`more %1 2^>nul`) more отображает содержимое файла, имя которого "Имя анализируемого файла" передано в первом аргументе процедуры %1. (смотрите more /? For /?)
2^>nul Подавит вывод сообщения об ошибке, если файл не найден. При этом после Do в For исполняться ничего не будет

В "анализируемом файле" искомые параметры содержатся в строке вида
%let Параметр = значение;
Её надо разобрать на подстроки по разделителям "=; "
1. %let
2. Параметр
3. значение
То есть в For имеем ... tokens=1,2,3 delims==; " и они помещаются в переменных %%i %%j %%k
Возможные неприятности:
Если в Параметре или значении есть пробел - работать будет неправильно из-за использования в качестве разделителя пробела.
Если в значении имеются спецсимволы типа % и др. работать будет неправильно из-за особенностей разбора текста в CMD.
(Описанный баг не баг вовсе а фича :)
Вложенный в первый For второй For вызавает процедуру :Ident куда передаёт последовательно каждое имя параметра %%a из полученного списка %~2 (передали ""Парам1" "Парам2" ..."ПарамN"" , после ~ имеем "Парам1" "Парам2" ..."ПарамN") и куски строк из файла в аргументах "%%i" "%%j" "%%k"
В процедуре :Ident
%2 -первый кусок строки (если это было %let то при передаче % потерялось)
Итак, если первый кусок строки == "let" (let ранее запомнил в переменную %Key%, стараюсь исходные данные вытянуть за код, чтобы можно было легко изменить при надобности - здесь, похоже, это паранойя), сравнение без учета регистра If /I (смотрим If /?)
If /I %2=="%Key%"
и если переданное имя параметра совпадает с именем параметра в строке If /I %1==%3 (%3 кусок строки с именем параметра, если строка начинается на let)
то переменной с именем нужного параметра %~1 присваиваем найденное значение Set "%~1=%~4"

Лирическое отступление 1. Я стремлюсь операторы типа Set Строка=Значение писать в виде Set "Строка=Значение", что позволяет гарантировать отсутствие невидных пробелов после Значение.
Лирическое отступление 2. Извините за длинноты объяснения, не было времени написать кратко


Burning Hell 28-07-2017 14:32 2754626

Цитата:

Цитата megaloman
Я не сильно всматривался, но очевидное отличие в двоеточии goto :start »

Двоеточие - оно и у меня в файле есть и в коде Iska...Или я вас не так понял.


megaloman, спасибо за подробное объяснение вашего кода! Я в CMD новичок, прогую на других языках, CMD дается тяжелее из-за сильных различий по отношению к другим языкам.

Несколько вопросов по поводу вашего кода.

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

Цитата megaloman
"%%i" "%%j" "%%k" »

Можно же писать и так: "%i%" "%j%" "%k%"? В чем разница ?

Не понял для чего нужна тильда:
Цитата:

Цитата megaloman
"%~1=%~4" »

?

И зачем нужно
Цитата:

Цитата megaloman
%%a »

при вызове процедуры Ident ?

Iska 28-07-2017 14:41 2754629

Цитата:

Цитата Burning Hell
Поясните пожалуйста, для чего нужно два знака процента у переменных:
Цитата megaloman:
"%%i" "%%j" "%%k" »
Можно же писать и так: "%i%" "%j%" "%k%"? В чем разница ? »

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

Цитата:

Цитата Burning Hell
Не понял для чего нужна тильда:
Цитата megaloman:
"%~1=%~4" »
? »

Для того, чтобы убрать кавычки (буде таковые) в значениях переменных %1 и %4.

megaloman 28-07-2017 15:21 2754632

Цитата:

Цитата Burning Hell
И зачем нужно %%a при вызове процедуры Ident ? »

Для понимания проделайте код:
Код:

@Echo Off
cls

Call :get_params_from_main_config "D:\codes\common\init_environment.sas" ""lasr_port" "lasr_host""

pause
GoTo :Eof

:get_params_from_main_config
        Echo %1
        Echo %2
        Echo:
        Echo %~2
        For %%a In (%~2) Do Echo Call :Ident %%a "%%i" "%%j" "%%k"
GoTo :Eof

В цикле последовательно из списка, взятого из переданного аргумента %~2 подпрограммы в подпрограмму :Ident для каждой строки для сравнения передаём имя искомого параметра.
Зачем нужна ~
Проделайте команду For /? >D:\_For.help и почитайте файл D:\_For.help Там ближе к концу это описано.
Смысл совпадает как для переменных цикла, так и для аргументов подпрограммы

Iska 28-07-2017 15:40 2754636

Цитата:

Цитата megaloman
Для понимания проделайте код:
Код:

… Call :Ident …
»

:Ident по пути потерялась?

megaloman 28-07-2017 15:52 2754637

Iska, там эхо для иллюстрации работы For, реального вызова :Ident нет

Burning Hell 28-07-2017 16:13 2754642

Цитата:

Цитата megaloman
Если в значении имеются спецсимволы типа % и др. работать будет неправильно из-за особенностей разбора текста в CMD. »

Еще такой вопрос. В значение хоста есть дефис и точки. Будут ли с ними проблемы?

megaloman 28-07-2017 18:17 2754663

Burning Hell,
Я тестировал на Вашем примере, для точек и минусов проблем нет
Код:

%global vaRepLib vaRepLib lasr_port lasr_engine lasr_tag lasr_host lasr_signer lasr_options metaport metaprotocol metarepository lasr_sig_files_path;
                       
%let vaRepLib = lasrlib;
%let lasr_port = 2289;
%let lasr_engine = sasiola;
%let lasr_tag = va_pub;
%let lasr_host = sas-vaar.dev.rnw;
%let lasr_signer = %str("http://sas-metadata.dev.rnw:85/SASLASRAuthorization");
%let lasr_options = %str(tag=&lasr_tag port=&lasr_port host="&lasr_host" signer=&lasr_signer);

Пытался понять, где у Вас не получалось. Слегка для себя модернизировал Ваш (после Iska и вставки моей процедуры) код. Естественно, полноценно тестировать не в состоянии, нет sas.exe. Работает.
Код:

@Echo Off
cls

Set /A Iter=0

:Begin
If %Errorlevel%==2 GoTo :Eof

Set /A Iter+=1
Echo +++ Begin %Iter% Iteration

Set "DD=%Date:~0,2%"
set "MM=%Date:~3,2%"
set "YYYY=%Date:~6,4%"

Set "HH=%Time: =0%"
Set "MN=%HH:~3,2%"
Set "SS=%HH:~6,2%"

Set "HH=%HH:~0,2%"
Set "FMT=AM"

If %HH% GTR 12 (
        Set "FMT=PM"
        Set /A HH=%HH%-12+100
)
If %HH% GTR 100 Set "HH=%HH:~1,2%"
If %HH%==00 Set "HH=12"

Set "LogFile=D:\logs\check_va_lasr_status_%YYYY%-%MM%-%DD%__%HH%.%MN%.%SS% %FMT%.log"

Call "D:\SAS\sas.exe" -sysin "D:\codes\check_va_lasr\check_va_lasr_status.sas" -log "%LogFile%"

Call :get_params_from_main_config "D:\codes\common\init_environment.sas" ""lasr_port" "lasr_host""

>nul 2>&1 findstr.exe /i /l /c:"error" /c:"connection" /c:"lasr" /c:"%lasr_port%" /c:"%lasr_host%" "%LogFile%" && (
        Call "D:\SAS\sas.exe" -sysin "D:\codes\check_va_lasr\check_lasr_log_and_run.sas" -nolog
        CHOICE /C YN /T 15 /D N /M "Iteration %Iter% finished with Errors. Y - Continue, N - Cancel."
        Echo:
        GoTo :Begin
) || (
        Echo +++ Iteration %Iter% finished successfully
        GoTo :Eof
)

GoTo :Eof

:get_params_from_main_config
        Set "Key=let"
        FOR /F "usebackq tokens=1,2,3 delims==; " %%i IN (`more %1 2^>nul`) DO (
                For %%a In (%~2) Do Call :Ident %%a "%%i" "%%j" "%%k"
        )
GoTo :Eof

:Ident
        If /I %2=="%Key%" If /I %1==%3 Set "%~1=%~4"
GoTo :Eof


Burning Hell 07-08-2017 15:09 2756915

Цитата:

Цитата Iska
Или ещё.
Код:
type "%full_log_path%" | >nul 2>&1 findstr.exe /i /l /c:"word1" /c:"word2" /c:"word3" && echo Found || echo Not found »

Сейчас тестировал этот момент и обнаружил, что даже если в целевом файле найдено хотя бы одно слово из трех (например, первое), то уже выводится "Found". Как сделать, чтобы "Found" выводилось только при нахождении всех трех слов (логическое "И")?

Iska 07-08-2017 16:07 2756932

Цитата:

Цитата Burning Hell
Сейчас тестировал этот момент и обнаружил, что даже если в целевом файле найдено хотя бы одно слово из трех (например, первое), то уже выводится "Found". »

Именно так.

Цитата:

Цитата Burning Hell
Как сделать, чтобы "Found" выводилось только при нахождении всех трех слов (логическое "И")? »

Можно, конечно, сделать и одним findstr, но уж больно монструозно будет, поскольку потребует 6 (3! = 6) перестановок:
Код:

type "%full_log_path%" | >nul 2>&1 findstr.exe /i /r /c:"word1.*word2.*word3" /c:"word1.*word3.*word2" /c:"word2.*word1.*word3" /c:"word2.*word3.*word1" /c:"word3.*word1.*word2" /c:"word3.*word2.*word1" && echo Found || echo Not found
А для 4 слов понадобится уже 4! = 24 перестановки, что не есть хорошо и правильно.

Посему проще будет так:
Код:

set /a bFound = 0

type "%full_log_path%" | >nul 2>&1 find.exe /i "word1" && set /a bFound = 1
type "%full_log_path%" | >nul 2>&1 find.exe /i "word2" && set /a bFound = 1
type "%full_log_path%" | >nul 2>&1 find.exe /i "word3" && set /a bFound = 1

if "%bFound%" equ "1" (
        echo Found
) else (
        echo Not found
)

Можно усложнить, убрав лишние проходы:
Код:

set /a bFound = 0

type "%full_log_path%" | >nul 2>&1 find.exe /i "word1" && (
        type "%full_log_path%" | >nul 2>&1 find.exe /i "word2" && (
                type "%full_log_path%" | >nul 2>&1 find.exe /i "word3" && set /a bFound = 1
        )
)

if "%bFound%" equ "1" (
        echo Found
) else (
        echo Not found
)

Ни то, ни другое не проверялось (оставляю это Вам).

P.S. Интересно, то будет в этом случае:
Код:

type "%full_log_path%" | >nul 2>&1 findstr.exe /i /v /l /c:"word1" /c:"word2" /c:"word3" && echo Not found || echo Found
Опять же, не проверялось.

Burning Hell 07-08-2017 16:12 2756935

Iska, спасибо...Была у меня мысль, что придется для каждого слова отдельный findstr писать, но думал, что можно как-то соптимизировать. Ладно, это не критично. Еще раз спасибо.

megaloman 07-08-2017 21:06 2757002

Burning Hell,
Вот мой вариант AND для произвольного числа искомых слов в файле
Код:

@Echo Off
cls

Set /A Iter=0

:Begin
If %Errorlevel%==2 GoTo :Eof

Set /A Iter+=1
Echo +++ Begin %Iter% Iteration

Call :StrDate "DateTime"
Set "LogFile=D:\logs\check_va_lasr_status_%DateTime%.log"

Call "D:\SAS\sas.exe" -sysin "D:\codes\check_va_lasr\check_va_lasr_status.sas" -log "%LogFile%"

Call :get_params_from_main_config "D:\codes\common\init_environment.sas" ""lasr_port" "lasr_host""

Call :IfAND "%LogFile%" "error" "connection" "lasr" "%lasr_port%" "%lasr_host%" && (
        Call "D:\SAS\sas.exe" -sysin "D:\codes\check_va_lasr\check_lasr_log_and_run.sas" -nolog
        CHOICE /C YN /T 15 /D N /M "Iteration %Iter% finished with Errors. Y - Continue, N - Cancel."
        Echo:
        GoTo :Begin
) || (
        Echo +++ Iteration %Iter% finished successfully
        GoTo :Eof
)

GoTo :Eof

:get_params_from_main_config
        Set "Key=let"
        FOR /F "usebackq tokens=1,2,3 delims==; " %%i IN (`more %1 2^>nul`) DO (
                For %%a In (%~2) Do Call :Ident %%a "%%i" "%%j" "%%k"
        )
GoTo :Eof

:Ident
        If /I %2=="%Key%" If /I %1==%3 Set "%~1=%~4"
GoTo :Eof

:IfAND
        >nul 2>&1 findstr.exe /i /l /C:%2 %1 || Exit /B 1
        Shift /2
        If Not "%2"=="" GoTo :IfAND
Exit /B 0

:StrDate
        FOR /F "tokens=2 delims==." %%d in ('WMIC OS GET LOCALDATETIME /VALUE') DO SET @Tdate=%%d
        Set "@Ttime=1%@Tdate:~8,6%"
        Set "@Tdate=%@Tdate:~0,4%-%@Tdate:~4,2%-%@Tdate:~6,2%"
        If %@Ttime% LSS 1120000 (Set "%~1=%@Tdate%__%@Ttime:~1,2%.%@Ttime:~3,2%.%@Ttime:~1,2% AM" &GoTo :Eof)
        Set /A @Ttime=%@Ttime%-120000
        Set "%~1=%@Tdate%__%@Ttime:~1,2%.%@Ttime:~3,2%.%@Ttime:~1,2% PM"
GoTo :Eof

где ввызове подпрограммы
Код:

Call :IfAND "%LogFile%" "error" "connection" "lasr" "%lasr_port%" "%lasr_host%"
- в первом аргументе - имя файла "%LogFile%",
- в остальных аргументах -искомые слова в кавычках. Здесь пять слов. Уберите лишние.
Процедура возвращает %ErrorLevel%==0 если все слова найдены, иначе %ErrorLevel%==1
Iska, А зачем при поиске нужен конвейер
Код:

type "%full_log_path%" | >nul 2>&1 find.exe
type "%full_log_path%" | >nul 2>&1 findstr.exe

Когда можно напрямую сослаться на файл "%full_log_path%" в find.exe и findstr.exe ?

Iska 07-08-2017 21:22 2757004

Цитата:

Цитата megaloman
Iska, А зачем при поиске нужен конвейер »

Сила привычки. В данном случае несущественно, но вообще find.exe в этом случае «гадит» в stdout именем файла, предварённым символами «-».


Время: 15:08.

Время: 15:08.
© OSzone.net 2001-