The SET search and replace trick works in many cases, but it does not support case sensitive or regular expression searches.
If you need a case sensitive search or limited regular expression support, you can use FINDSTR.
To avoid complications of escaping special characters, it is best if the search string is in a variable and both search and target are accessed via delayed expansion.
You can pipe $1 into the FINDSTR command with the ECHO command. Use ECHO(
in case $1 is undefined, and be careful not to add extra spaces. ECHO !$1!
will echo ECHO is off.
(or on) if $1 is undefined, whereas ECHO(!$1!
will echo a blank line if undefined.
FINDSTR will echo $1 if it finds the search string — you don’t want that so you redirect output to nul. FINDSTR sets ERRORLEVEL to 0 if the search string is found, and 1 if it is not found. That is what is used to check if the string was found. The &&
and ||
is a convenient syntax to use to test for match (ERRORLEVEL 0) or no match (ERRORLEVEL not 0)
The regular expression support is rudimentary, but still useful.
See FINDSTR /? for more info.
This regular expression example will search $1 for «BEGIN» at start of string, «MID» anywhere in middle, and «END» at end. The search is case sensitive by default.
set "search=^BEGIN.*MID.*END$"
setlocal enableDelayedExpansion
echo(!$1!|findstr /r /c:"!search!" >nul && (
echo FOUND
rem any commands can go here
) || (
echo NOT FOUND
rem any commands can go here
)
Есть список баз в файле db.txt. Вот его содержание
DOC
VOC
DAT1
DAT2
DAT3
DAT4
Пробегаюсь по нему
for /f "tokens=1 delims=/.- " %%a in ('type db.txt') do (
)
Надо, например, вывести только базы начинающиеся с DAT. Я нашёл как найти подстроку
echo %%a | findstr /i DAT
И вот вопрос, как мне результат поиска подстроки подставить в конструкцию IF?
Заранее спасибо!
-
Вопрос заданболее трёх лет назад
-
23688 просмотров
0) Идея: в каждом IF’е брать подстроку. К сожалению, подстроку в цикле взять довольно сложно (даже enabledelayedexpansion не помогает, плюс прочие багофичи), но мы можем снова заюзать findstr по строке! (echo ololo | findstr lol > NUL)
1) findstr устанавливает return code при выходе (а он записывается шеллом в ERRORLEVEL). 0 == нашел, 1 == не нашел
2) ERRORLEVEL работает довольно интересно:
условие вида IF NOT ERRORLEVEL 1 это значит ERRORLEVEL == 0
3) Собираем все вместе:
@echo off
set usr=%1
for /f "tokens=1 delims=/.- " %%a in ('type db.txt') do (
echo %%a | findstr VOC > NUL
if NOT ERRORLEVEL 1 (
echo TEST! with %%a we do:
echo TEST! db2 grant execute on function "WEB.F1(INTEGER)" to user %usr% with grant option
echo TEST! db2 grant execute on function "WEB.F2(INTEGER)" to user %usr% with grant option
echo TEST!
) else (
echo %%a | findstr DAT > NUL
if NOT ERRORLEVEL 1 (
echo TEST! with %%a we do:
echo TEST! db2 grant execute on function "WEB.F3(INTEGER)" to user %usr% with grant option
echo TEST!
)
)
)
Результат:
B:>test.bat user1
TEST! with VOC we do:
TEST! db2 grant execute on function "WEB.F1(INTEGER)" to user user1 with grant option
TEST! db2 grant execute on function "WEB.F2(INTEGER)" to user user1 with grant option
TEST!
TEST! with DAT1 we do:
TEST! db2 grant execute on function "WEB.F3(INTEGER)" to user user1 with grant option
TEST!
TEST! with DAT2 we do:
TEST! db2 grant execute on function "WEB.F3(INTEGER)" to user user1 with grant option
TEST!
TEST! with DAT3 we do:
TEST! db2 grant execute on function "WEB.F3(INTEGER)" to user user1 with grant option
TEST!
TEST! with DAT4 we do:
TEST! db2 grant execute on function "WEB.F3(INTEGER)" to user user1 with grant option
TEST!
Пригласить эксперта
Согласно справке из findstr /? результат запуска:
findstr /b DAT
выведет строки начинающиеся на DAT.
Соответственно, ваш скрипт будет иметь вид:
for /f "tokens=1 delims=/.- " %%a in ('type db.txt') do (echo %%a | findstr /b DAT)
В принципе, этот скрипт можно даже сделать более универсальным, передавая скрипту искомое значение в виде параметра к нему:
for /f "tokens=1 delims=/.- " %%a in ('type db.txt') do (echo %%a | findstr /b %1)
Откройте для себя повершелл со всей дурью Net, в том числе с подстроками, регекспами (http://xaegr.wordpress.com/2010/04/09/regexp-8-regex/)
.
foreach ($line in Read-content filesource.txt)
{
…
}
-
Показать ещё
Загружается…
25 мая 2023, в 12:34
2000 руб./в час
25 мая 2023, в 12:25
2000 руб./в час
25 мая 2023, в 12:09
3000 руб./за проект
Минуточку внимания
Позавчера мне пришлось написать простенький командный файл, бекапящий профиль приложения. В качестве имени папки с резервной копией мне возжелалось использовать переменные окружения %date% и %time%. Если вы проходили в институте начальный курс информатики, вы должны знать, что %time% в этом случае является ничем иным, как граблями, остро торчащими на пути, так значение содержит недопустимый символ «:». Я никогда не занимался разбором строк в командных файлах, и случай как нельзя лучше подходил для того, чтобы прокачать свои скилы.
Я хочу поделиться с вами своими изысканиями, и анонсирую скучную, унылую техническую статью. Дочитавшему до конца — покажу котика.
В современных ОС интерпретатор командной строки позволяет выполнять простейшие строковые операции:
- Замену подстроки в строке
- Поиск подстроки
- Выделение подстроки
- Работа с наборами «ключ — значение»
Замена символов/подстроки в переменной командной строки
Это то, что мне было нужно в первую очередь. Напомню, моя задача в первую очередь избавиться от двоеточий.
Решается очень просто:
[code]set mytime=%time::=_%[/code]
В этом примере используется синтаксис вида:
[code]%Переменная:ЧтоНайти=НаЧтоЗаменить%[/code]
В моем случае заменяется двоеточие на символ нижнего подчеркивания, и результат выглядит так:
Само собой, можно заменять не отдельные символы, а целые словосочетания:
Как ещё можно воспользоваться функцией замены? Например:
Удалить все пробелы из значения переменной
[code]echo %var: =%[/code]
Замена какой-либо части строки
Вы можете использовать символ «*» для определения того, что обработке подлежит часть строки, предшествующая указанному выражением. Я не знаю, как написать это по-человечески, вот что я имею ввиду:
К сожалению, «звёздочкой» нельзя указать, что отсечь надо часть строки после указанного выражения. Эта задача решается в два этапа:
- в отдельную переменную помещается строка, из которой удалено всё, что находится до ключевого выражения. Т.е. в ней остается «хвост», искомое выражение плюс всё, что после него.
- затем из оригинальной переменной удаляется значение переменной, полученной на первом шаге. Здесь потребуется вызов команды СALL:
Инструкция CALL необходима для разворачивания значения переменной, подлежащей замене. Без неё интерпретатор отработает неверно, и вот эта конструкция не сработает:
[code]echo %var1:%var%=%[/code]
Необходимо писать:
[code]call echo %var1:%var%=%[/code]
Не забывайте, что при использовании таких конструкций в командных файлах знаки процентов должны быть удвоены:
[code]rem Работаем внутри командного файла
call echo %%var1:%var%=%%[/code]
Поиск подстроки
Используя опыт, полученный выше, можно написать простейшую проверку вида «содержит/не содержит».
Например, вот так:
[code]set var1=Мама мыла раму
set var2=%var1:Мама=%
if NOT «%var1%» == «%var2%» (echo Подстрока найдена)[/code]
Или
[code]set var1=Мама мыла раму
set var2=%var1:Мама=%
if NOT «%var1%» == «%var2%» (echo Подстрока найдена) else (echo Подстрока не найдена) [/code]
Выделение подстроки из переменной
Для получения подстроки из строки командный интерпретатор предоставляет такую конструкцию:
[code]set var2=%var1:~начальная_позиция%
set var2=%var1:~начальная_позиция,-отбросить_символов_с_конца_строки%
set var2=%var1:~начальная_позиция,длина%[/code]
Синтаксис очень простой, поэтому сразу перейдем к примерам.
Выделение подстроки с начиная определенной позиции
Выделение части строки, например, «середины»
Выделение определенного количества символов
Начальная позиции строки — нулевая.
Работа с наборами «ключ — значение»
Здесь, в общем-то, тоже никакой магии нет. В основе разбора лежит всё та же рассмотренная выше замена подстроки на пустое значение.
Алгоритм действий такой:
- Создается переменная, содежащая в себе значения вида <ключ><разделитель значения><значение><разделитель пары>. Назовем её условно «словарь».
- В переменную, которая будет содержать значение, записывается всё, что следует после ключа. По аналоги с заменой части строки, нужно использовать звездочку перед выражением <ключ><разделитель значения>.
- Полученный результат нужно «почистить», так как он может содержать в себе остаток словаря. Для этого прибегнем к хитрости и выполним составную команду.
Предположим, мы в качестве разделителя пары словаря используем точку с запятой. Тогда мы сможем довольно изящно «убить» оставшуюся часть словаря, поместив его в комментарии командой rem.
[code]set value=%value:;=&rem %[/code]
После rem — пробел, это важно(rem /?)
Теперь практический пример:
Я надеюсь, эта информация оказалась для вас полезной и сэкономит вам время, если у вас появится задача обработки строк. Впрочем, тему я раскрыл не полностью, и если у вас есть какие-то дельные личные наработки и приёмы обработки строк в командном интерпретаторе Windows, я совсем не против увидеть их в комментариях.
Материалы по теме:
http://ss64.com/nt/
Форум о скриптах на OSZone — рекомендую.
Спасибо, что дочитали до конца.
💡Узнавайте о новых статьях быстрее. Подпишитесь на наши каналы в Telegram и Twitter.
Судя по тому, что вы читаете этот текст, вы дочитали эту статью до конца. Если она вам понравилась, поделитесь, пожалуйста, с помощью кнопок ниже. Спасибо за вашу поддержку!
YuS_2, большое спасибо!
Теперь понятно, как это работает ))
Действительно, если переменная хранит пустоту, то для батника она считается неопределенной.
Результатом операций над неопределенной переменной (таких как замена текста, взятие подстроки, etc)
получается текст, который идет после двоеточия.
Windows Batch file | ||
|
вывод в консоль:
Код
variable 'var' not defined result: 'str1=str2' last_character: '~-1'
Значит, прежде чем выполнять какие либо подобные операции над строками,
необходимо убедиться, что переменные не содержат пустоты.
Добавлено через 10 минут
Сообщение от alpap
да ладно, серьезно, с первого раза непонятно?
Серьёзно.
Я не обнаружила связи вашего предыдущего сообщения с моим вопросом.
Поэтому, перефразировала свой вопрос.
Вы пишите:
создать новую переменную из переменной, значение которой пустота и на этом пустом месте сделать замену одного на другое
Для меня это звучит, как какой-то дикий бред.
Что бы поменять «одно» на «другое», нужно чтобы это «одно» вообще было.
Иначе заменять будет нечего.
В операции: «заменить всех собачек на кошечек» вы не сможете ничего заменить, если нет ни одной собачки.
В строке «hello world» очень просто заменить слово «world» на «CyberForum».
Получится «hello CyberForum»
И батник это подтверждает:
Windows Batch file | ||
|
вывод в консоль:
Но тогда, если в изначальном тексте «hello world» заменить текст «WTF» на текст «CyberForum»,
то получится тот же самый «hello world». Потому что в исходном тексте нет подстроки «WTF».
[b]Нельзя заменить то, чего нет на что-то иное[b].
[b]Нельзя заменить несуществующую собачку на кошечку[b].
И батник опять таки это подтверждает:
Windows Batch file | ||
|
вывод в консоль:
Ваше сообщение никак не объясняет: как же тогда случилось так, что вместо ожидаемой замены собачек на кошечек,
в переменной оказалось что-то совершенно непонятное.
Даже близко не похожее на результат замены.
— В этом нет логики
— А кто говорил что она там есть?
Я действительно не поняла с первого раза, что именно вы пытались объяснить.
I had to create a function:
Use it as:
SearchText = "Why does the purple cow jump over the moon?"
SearchTerm = "Purple"
CALL:checkIfStringCotainsText "%SearchText%" "%SearchTerm%" RESULT
IF %RESULT%==true(
ECHO Text Found!
) ELSE (
ECHO Text NOT Found.
)
Remember it is not case sensitive by default. Add the word true to the end of the Call if you would like to be case sensitive such as:
SearchText = "Why does the purple cow jump over the moon?"
SearchTerm = "Purple"
CALL:checkIfStringCotainsText "%SearchText%" "%SearchTerm%" RESULT true
REM # Returns false because Purple is capitalized
And these Functions to the bottom of your Batch File.
:FUNCTIONS
@REM FUNCTIONS AREA
GOTO:EOF
EXIT /B
:checkIfStringCotainsText
@REM # CHECKS IF A STRING CONTAINS A SUBSTRING
@REM # Returns the %3 as either set to true or false
@REM # Not case sensetive by defualt. But can be set to case sensetive buying adding true as the fourth paramater
@REM # For example: CALL:checkIfStringCotainsText "Whats up SLY Fox?" "fox" RESULT true
@REM # SearchText SearchTerm
true-or-false CaseSensetive?
@Rem # Will check if "Whats up SLY Fox?"" contains the text "fox"
@REM # Then check the result with: if %RESULT%==true (Echo Text Found) Else (Text Not Found)
@REM # Remember do not add %RESULT% use only RESULT .Do not add % around RESULT when calling the function.
@REM # Only add % around RESULT when checking the result.
@REM # Make sure to add "SETLOCAL ENABLEDELAYEDEXPANSION" to the top of your Batch File! This is important!
@REM # Make sure you use quotes around SearchText and SearchTerm. For example "SearchText" not SearchText.
@REM # This is because if there is a space inside the SearchText, each space will make it look like a new parameter
SET SearchString=%~1
SET SearchTerm=%~2
@REM #Check if Case Senseitive
IF [%~4]==[true] (
@REM if %~4 is not set to anything, treat it as the default as false
@REM - Do nothing as FindStr is normally case sensetive
) ELSE (
@REM Change both the text and search-term both to lowercase.
CALL:LCase SearchString SearchString
CALL:LCase SearchTerm SearchTerm
)
@set containsText=false
@echo DEBUG: Searching for ^|%~2^| inside ^|%~1^|
@echo "!SearchString!" | find "!SearchTerm!" > nul && if errorlevel 0 (set containsText=true)
SET %3=!containsText!
@GOTO:EOF
:LCase
:UCase
@REM Converts Text to Upper or Lower Case
@REM Brad Thone robvanderwoudeDOTcom
:: Converts to upper/lower case variable contents
:: Syntax: CALL :UCase _VAR1 _VAR2
:: Syntax: CALL :LCase _VAR1 _VAR2
:: _VAR1 = Variable NAME whose VALUE is to be converted to upper/lower case
:: _VAR2 = NAME of variable to hold the converted value
:: Note: Use variable NAMES in the CALL, not values (pass "by reference")
SET _UCase=A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
SET _LCase=a b c d e f g h i j k l m n o p q r s t u v w x y z
SET _Lib_UCase_Tmp=!%1!
IF /I "%0"==":UCase" SET _Abet=%_UCase%
IF /I "%0"==":LCase" SET _Abet=%_LCase%
FOR %%Z IN (%_Abet%) DO SET _Lib_UCase_Tmp=!_Lib_UCase_Tmp:%%Z=%%Z!
SET %2=%_Lib_UCase_Tmp%
GOTO:EOF
And remember you MUST add «SETLOCAL ENABLEDELAYEDEXPANSION» to the top of your batch file or else none of this will work properly.
SETLOCAL ENABLEDELAYEDEXPANSION
@REM # Remember to add this to the top of your batch file.