为什么Windows批处理文件输出的行数组中缺少特殊字符?

时间:2018-10-04 14:17:18

标签: windows batch-file

我想将.txt文件中存在的数据(仅具有扩展关键字的行)以 ID,数据,日期,项目名称的格式插入到Oracle数据库中,其中存在ID,日期和项目名称在环境变量中。

File.txt具有以下数据:

Writing main object(name=abc)
writing Extended object (name=%abc(123&rest,type=pqr)

logdata.txt应该包含以下数据:

A1234C,(name=%abc(123&rest,type=pqr),12022018_11:12:20,DEV:Sales Project

在复制数据时,输出文件logdata.txt中缺少file.txt中出现的特殊字符,例如%,(等)。

请找到以下代码:

set file=D:\MSTR_CICD\file.txt
for /F "usebackq tokens=2*delims=(" %%a in (`findstr  "extended" "%file%"`) do (
    set /A i+=1
    call set array[%%i%%]=%%a
    call set n=%%i%%
)

for /L %%i in (1,1,%n%) do call echo %User_ID%,%%array[%%i]%%,%Timestamp%,%proj%  >> D:\MSTR_CICD\Batch_Script\logdata.txt

请更正代码或让我知道我该如何实现。另外,我的输入文件可以包含任何应用程序日志,因此可以有任何特殊字符。

1 个答案:

答案 0 :(得分:0)

此批处理文件可用于此任务:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "proj=DEV:Sales Project"
set "User_ID=A1234C"
set "Timestamp=12022018_11:12:20"
set "InputFile=D:\MSTR_CICD\file.txt"
set "DataFile=D:\MSTR_CICD\Batch_Script\logdata.txt"

if exist "%InputFile%" (
    for /F delims^=^ eol^= %%I in ('%SystemRoot%\System32\findstr.exe /I /C:Extended "%InputFile%"') do (
        set "DataLine=%%I"
        setlocal EnableDelayedExpansion
        set "DataLine=!DataLine:*(=(!"
        set "DataLine=!DataLine:"=""!"
        echo %User_ID%,"!DataLine!",%Timestamp%,%proj%
        endlocal
    )
) >"%DataFile%"

if exist "%DataFile%" for %%I in ("%DataFile%") do if %%~zI == 0 del "%DataFile%"

:EndBatch
endlocal

FINDSTR 在由 FOR 启动的单独命令过程中在后台运行,cmd.exe /C不区分大小写,直接搜索字符串Extended输入文件上,并输出包含该字符串的所有行以处理 STDOUT

FOR 捕获此输出并逐行处理它们。 FOR 会忽略空行,并且默认情况下也会以分号开头的行,因为;是默认的行尾字符。并且 FOR 使用空格/制表符作为分隔符将行拆分为子字符串(令牌),并且默认情况下仅将第一个子字符串分配给指定的循环变量。

通过使用 FOR 选项字符串delims^=^ eol^=,可以使用一个空的定界符列表,并且不设置任何行尾字符来禁用行拆分并忽略以分号开头的行。由于此特殊选项字符串不能用双引号引起来,因此必须转义空格和两个带有尖号字符的等号,以使这三个字符在双引号参数字符串之外解释为文字字符而不是参数字符串分隔符。 / p>

在文件中找到的 FINDSTR 输出的整个行都分配给环境变量DataLine。这是通过禁用延迟的环境变量扩展来完成的,也可以处理包含一个或多个感叹号的正确行。否则,cmd.exeset "DataLine=%%I"替换为当前行后将对行%%I进行双重解析,并将行中的每个!解释为环境变量引用的开始/结束在将该行分配给环境变量之前进行了不必要的修改。

在命令 SET 的行上使用命令 CALL 还会导致在执行命令 SET 之前对命令行进行双重解析。代码生成的环境变量数组中缺少某些字符的原因。

有关详细信息,另请参见How does the Windows Command Interpreter (CMD.EXE) parse scripts?

将行分配给环境变量后,有必要启用delayed expansion以进一步处理 FOR 循环中的数据行。这会使批处理文件变慢,但在这种情况下无法避免。阅读this answer,了解有关命令 SETLOCAL ENDLOCAL 的详细信息。

数据行的第一个修改是删除第一个(左边的所有内容。

数据行的第二个修改是将行中的所有"替换为"",以根据CSV规范转义每个双引号。

然后将剩余的数据行与其他用双引号引起来的数据一起输出,因为该数据行还可以包含一个或多个逗号,根据CSV规范,该数据要求将数据用双引号引起来。

有关CSV规范,请阅读Wikipedia关于comma-separated values的文章。

FOR 循环中 ECHO 的所有输出都将重定向到指定的数据文件,该文件将偶然覆盖已经存在的同名数据文件。

在任何情况下, FINDSTR 都可能找不到包含Extended的任何行,从而导致产生一个0字节的数据文件。空数据文件被第二个 FOR 删除。

要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。

  • del /?
  • echo /?
  • endlocal /?
  • findstr /?
  • for /?
  • goto /?
  • if /?
  • set /?
  • setlocal /?