Вот мое решение для этой задачи замены строки, используя только внутренние команды cmd.exe
, за исключением FINDSTR .
@echo off
setlocal EnableExtensions DisableDelayedExpansion
if not defined workingPlace set "workingPlace=%~dp0"
set "TextFile=%workingPlace%bin\csm.properties"
if not exist "%TextFile%" goto EndBatch
set "TempFile=%TEMP%\csm.properties.tmp"
set "FoundInfo="
(for /F delims^=^ eol^= %%I in ('%SystemRoot%\System32\findstr.exe /N "^" "%TextFile%"') do (
set "Line=%%I"
setlocal EnableDelayedExpansion
set "Line=!Line:*:=!"
if not defined FoundInfo (
if defined Line (
if /I "!Line:~0,10!" == "CLASSPATH=" (
if /I "!Line!" == "CLASSPATH=" (
echo !Line!plugins/Numbering.jar
endlocal
set "FoundInfo=1"
) else if "!Line:plugins/Numbering.jar=!" == "!Line!" (
set "Line=!Line:~0,10!plugins/Numbering.jar\:!Line:~10!"
echo !Line!
endlocal
set "FoundInfo=1"
) else (
endlocal
goto DeleteTempFile
)
) else (
echo(!Line!
endlocal
)
) else (
echo/
endlocal
)
) else (
echo(!Line!
endlocal
)
))>"%TempFile%"
if not defined FoundInfo echo CLASSPATH=plugins/Numbering.jar>>"%TempFile%"
move /Y "%TempFile%" "%TextFile%"
:DeleteTempFile
if exist "%TempFile%" del "%TempFile%"
:EndBatch
endlocal
Прочитать мой ответ на Как читатьи печатать содержимое текстового файла построчно? почему команда FINDSTR используется только для вывода каждой строки в файле csm.properties
, включая пустые строки, игнорируемые FOR по умолчанию со строкойномер и :
, чтобы любая строка не игнорировалась FOR .Номер строки и двоеточие удаляются командной строкой set "Line=!Line:*:=!"
.
В верхней части пакетного файла есть переменная окружения FoundInfo
undefined, которая устанавливается после того, как строка начинается без учета регистра с CLASSSPATH=
обрабатывается внутренним кодом цикла FOR .Каждая строка в файле после строки, начинающейся с CLASSSPATH=
, выводится без дальнейшей обработки, включая пустые строки.
Пустая строка над строкой, начинающейся с CLASSSPATH=
, также выводится с echo/
без дальнейшей обработки.
Первая строка, начинающаяся без учета регистра с CLASSPATH=
, может обрабатываться тремя различными способами:
- В строке содержится только
CLASSPATH=
.
В этом случае строкавыводится как CLASSPATH=plugins/Numbering.jar
и все. - Строка начинается с
CLASSPATH=
и содержит один или несколько символов, но без учета регистра строки plugins/Numbering.jar
.В этом случае строка выводится при вставке plugins/Numbering.jar\:
после CLASSPATH=
.
Обратите внимание, что строка с CLASSPATH=
и одним или несколькими конечными пробелами / табуляциями также приведет к переходу во вторую ветвь, что приведет, например, квывод CLASSPATH=plugins/Numbering.jar\:
с \:
и завершающими пробелами в конце. - Строка начинается с
CLASSPATH=
и содержит уже без учета регистра строку plugins/Numbering.jar
где-то в строке.
В этомв случае, если цикл FOR немедленно завершается с переходом к метке DeleteTempFile
без обработки какой-либо дополнительной строки из захваченного вывода FINDSTR .Таким образом, дата последнего изменения файла не изменяется из-за того, что ничего не изменилось в содержимом файла.(Мне не нравится изменение даты последнего изменения содержимого файла, которое на самом деле не было изменено.)
После того, как цикл FOR проверен на наличие какой-либо строки, начинающейся без учета регистра сCLASSPATH=
вообще в файле.Строка CLASSPATH=plugins/Numbering.jar
добавляется к временному файлу, если это не так.
Наконец, если временный файл определенно отличается от csm.properties
, временный файл перемещается поверх существующего файла csm.properties
, если это так.возможно вообще, и последний временный файл удаляется, если он все еще существует.
Примечание 1: Решение может быть проще без использования FINDSTR , если файл csm.properties
не содержит пустых строк или допускается удаление пустых строк при обновлении строки с CLASSPATH=
.
Примечание 2: Строка с CLASSPATH=
вверху файла csm.properties
сокращает время обработки.
Краткое описание возможностей этого решения:
- Не изменяет текстовый файл, содержащий уже
CLASSPATH=
, где plugins/Numbering.jar
где-то в строке. - Вставляет
plugins/Numbering.jar\:
после CLASSPATH=
, только если в этой строке есть другие пути классов (или конечные пробелы). - Добавляет
plugins/Numbering.jar
к существующей строке CLASSPATH=
, не содержащей какого-либо другого классапуть (и нет следавводя пробелы в этой строке). - Добавляет всю строку
CLASSPATH=
с plugins/Numbering.jar
к файлу, не содержащему эту строку вообще, если файл существует хотя бы. - Сохраняет пустые строки в текстовом файлеи поэтому действительно изменяет только строку с
CLASSPATH=
в начале. - Не изменяет строки с
VARIABLE==value
(значение со знаком равенства в начале) до VARIABLE=value
(знак равенства в начале удален). - Не изменяет орфографию
CLASSPATH=
и работает по этой причине также с classpath=
или ClassPath=
в файле. - Не удаляет строки, начинающиеся с
;
по умолчанию FORОпция конца строки (eol).
Чтобы понять используемые команды и то, как они работают, откройте окно командной строки, выполните там следующие команды и внимательно прочитайте все страницы справки, отображаемые для каждой команды.
del /?
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
move /?
set /?
setlocal /?
См. Также Почему не выводится строкас 'echo% var%' после использования 'set var = text' в командной строке? и Как установить переменные окружения с пробелами? Эти ответы объясняют, почему в большинстве случаев set variable="value"
не подходити в чем отличие от set "variable=value"
, который является предпочтительным синтаксисом для определения переменной среды со строковым значением.
См. также Символ, эквивалентный NEQ, LSS, GTR и т. д. в пакете Windowsфайлы , объясняющие, как работает сравнение строк с командой IF и почему операторы EQU
и NEQ
разработали primary для целочисленных сравнений вообще не следует использовать для сравнения двух строк, хотя это возможно.Использование EQU
и NEQ
для сравнения строк в некоторых случаях может привести к неожиданному результату сравнения строк без двойных кавычек.