0

基本上:

第一次在这里发布海报......我不仅在搜索 SO,而且在整个互联网上搜索过去 2 天的答案。我想要一个在卸载期间运行的批处理文件(.bat),打开一个配置(.cfg)文件,找到一个条目并将其删除,然后完成卸载。

到目前为止我所拥有的:

我有一个运行批处理文件以将条目添加到配置文件中的安装程序:

[Area.01]
Title=Unique to entry
Location=Unique to entry
Active=Required but in all entries
Layer=Required with Unique Number
Required=Required but in all entries

[Area.02]
Title=Unique to entry
Location=Unique to entry
Active=Required but in all entries
Layer=Required with Unique Number
Required=Required but in all entries

我让安装批处理文件扫描配置并添加下一个条目号、条目的内容和保存条目索引的 REGISTRY 键;所以从逻辑上讲,下一个条目是[Area.03]. 但是,此文件包含 100 多个条目。

我想要的是批处理文件读取它所做的注册表条目,找到它所做条目,然后删除整个条目,这就是我在这里的原因。这是我到目前为止所拥有的:

@echo off

REG QUERY "HKLM\SOFTWARE\Name of File" /v SceneryCFGPath
IF ERRORLEVEL 1 GOTO ERROR1
FOR /F "tokens=3 skip=2" %%i IN ('REG QUERY "HKLM\SOFTWARE\Name of File" /v SceneryCFGPath') DO SET VAR1=%%i
CD "%VAR1%"

REG QUERY "HKLM\SOFTWARE\Name of File" /v SceneryIndex
IF ERRORLEVEL 1 GOTO ERROR2
FOR /F "tokens=3 skip=2" %%i IN ('REG QUERY "HKLM\SOFTWARE\Name of File" /v SceneryIndex') DO SET VAR2=%%i
TYPE scenery.cfg | FINDSTR /V Area.%VAR2%
REG DELETE "HKLM\SOFTWARE\Name of File" /F
GOTO END

:ERROR1
ECHO There was an Error while changing to Directory "%VAR1%"...
PAUSE
GOTO ERROR2

:ERROR2
ECHO There was an Error while unregistering from Scenery Library ! Please delete the Area manually...
PAUSE
GOTO END

:END
del "%~f0"

使用时,FINDSTR它成功找到了条目,但删除了第一行:[Area.03]. 我需要它做的是删除该条目和该条目的其他部分。

当我尝试在 FINDSTR 中包含其他条目时:

TYPE scenery.cfg | FINDSTR /V /N Area.%VAR2% | Title | Active | Layer | Required

它会删除每个条目的所有这些行。

我真的更喜欢这是一个批处理文件,因为它可以在 Windows XP、Vista 和 7、32 和 64 位系统上运行。 由于这些特定的 Windows 系统都具有CMD.EXE,因此不需要任何额外的库或程序。

除了删除配置文件中的整个条目外,我的一切工作正常。我希望我没有混淆任何人,但任何帮助将不胜感激!

斯文2157

4

1 回答 1

1

在解决您提出的问题之前,还有一些与您的错误处理有关的其他问题需要处理。

您测试是否存在特定的注册表键值,如果没有找到,则尝试打印出不存在的键值!那行不通;-)

您尝试 CD 到找到的路径值,但不能保证该路径是有效的。您可能想要检查错误。此外,当前驱动器可能与路径的驱动器不匹配,因此您应该使用 CD /D(或 PUSHD)。

每个注册表键值对使用 2 个 REG QUERY 操作 - 一个用于测试是否存在,另一个用于解析值。每个键值只需要 1 个 REG QUERY。

批处理文件在完成后会自行删除。这将导致“找不到批处理文件”错误。也许您不在乎,但是当您调用此批处理时,您可能应该将 stdout 重定向到 nul。

由于您的批处理文件会因删除而自行终止,因此您可以简化错误处理。每个错误都不需要单独的例程。只需调用一个通用错误例程,传入错误消息。错误例程可以在完成后进入结束例程,这会杀死批处理。因此无需担心从错误调用返回。

我已将上述所有想法合并到下面的代码中。

我还假设您实际上想要修改“scenery.cfg”文件,而不是简单地将更改后的表单回显到屏幕上。我将输出重定向到一个新文件,然后将新文件重命名为旧名称,从而破坏原始文件。

现在,要解决您最初的问题-批处理没有任何本机实用程序可以方便地提取两个标记线之间的一系列线。由于您不想依赖任何非本地实用程序,因此您必须循环处理每一行并确定是否应包含该行。

我看到了 2 种简单的方法来做到这一点:注意 - 没有代码经过测试。这些概念都很合理,但我可能引入了一个应该很容易修复的愚蠢错误

1 - 使用单个循环检查每一行,并在找到所选区域时开始排除该行,并在下一个区域开始时恢复

该代码使用 SET 搜索和替换来测试该行是否包含有问题的字符串。

读取文件的经典技术是 FOR /F 循环。但它去掉了空白行。因此代码被扩展为在每个 [Area.nn] 部分之前添加一个空行。!需要延迟扩展,但如果启用延迟扩展,包含的 FOR 变量值会损坏。所以我在循环中打开和关闭延迟扩展。如果您知道它!永远不会出现在文件中,那么您可以简单地在顶部启用延迟扩展并从循环中删除 SET LOCAL 和 ENDLOCAL。

@echo off
setlocal disableDelayedExpansion
set regPath="HKLM\SOFTWARE\Name of File"

set "myPath="
for /f "tokens=3 skip=2" %%A in ('reg query %regPath% /v SceneryCFGPath') do set "myPath=%%A"
if not defined myPath call :error Unable to locate SceneryCFGPath
cd /d "%myPath%" 2>nul || call :error Unable to CD to "%myPath%"

set "area="
for /f "tokens=3 skip=2" %%A IN ('reg query %regPath% /v SceneryIndex') do set "area=%%A"
if not defined area call :error Unable to unregister from Scenery Library ! Please delete the Area manually...

>scenery.cfg.new (
  set "del="
  for /f "delims=" %%A in (scenery.cfg) do (
    set "ln=%%A"
    setlocal enableDelayedExpansion
    if "!ln:[Area.%area%=!" neq "!ln!" (
        set del=1
    ) else if "!ln:[Area.=!" neq "!ln!" (
        set "del="
        echo(
    )
    if not defined del echo !ln!
    endlocal
  )
)
move /y scenery.cfg.new scenery.cfg

reg delete %regPath% /f
goto end

:error
echo ERROR: %*
pause

:end
del "%~f0"

2 - 使用 FINDSTR 查找所选区域的开头,使用 2nd FINDSTR 查找下一个区域的开头。

/N 选项用于获取匹配行的行号。FOR /F 用于解析结果并将其分配给一个值。一旦找到下一个区域,就需要 GOTO 跳出第二个循环。

最后,第三个 FOR /F 用于读取具有 FINDSTR 命令前置的行号的文件。解析每一行并排除适当的行。

请注意,如果一行以 . 开头,此代码将无法正常工作:。可以使用更多代码来消除限制,但我认为在您的情况下不需要它。

@echo off
setlocal disableDelayedExpansion
set regPath="HKLM\SOFTWARE\Name of File"

set "myPath="
for /f "tokens=3 skip=2" %%A in ('reg query %regPath% /v SceneryCFGPath') do set "myPath=%%A"
if not defined myPath call :error Unable to locate SceneryCFGPath
cd /d "%myPath%" 2>nul || call :error Unable to CD to "%myPath%"

set "area="
for /f "tokens=3 skip=2" %%A IN ('reg query %regPath% /v SceneryIndex') do set "area=%%A"
if not defined area call :error Unable to unregister from Scenery Library ! Please delete the Area manually...

set "beginDel="
for /f "delims=:" %%N in ('findstr /nbc:"[Area.%area%]" scenery.cfg') do set beginDel=%%N
if not defined beginDel goto end

set "endDel="
for /f "delims=:" %%N in ('findstr /nbc:"[Area." scenery.cfg') do if %%N gtr beginDel (
  set endCond=if %%A gre %%N
  goto :break
)
:break

>scenery.cfg.new (
  for /f "tokens=1* delims=:" %%A in ('findstr /n "^" scenery.cfg') do (
    if %%A lss %beginDel% %endCond% echo(%%B
  )
)
move /y scenery.cfg.new scenery.cfg

reg delete %regPath% /f
goto end

:error
echo ERROR: %*
pause

:end
del "%~f0"
于 2012-07-21T20:24:43.250 回答