我正在 Windows 上编写批处理脚本,有了它的帮助我想要将许多文件中的信息整理成较小的文件。 我在日志文件中有大约3000行,我需要从中获取一些东西,基本上有名称和值(例如“,INC_LIMI = 050,ISO_LIMI = 050,INC_MLIM = 074,”),并且所有内容都以“,”符号分隔。我的问题是如何读取长字符串行并只读取如下值:
String LineString[]
LineString = Line.split(,)
String s = "INC_MLIM"
For elem in LineString
if elem.exist(s)
NewLine.append(elem)
,后者只保存到新文件。
修改: 有service.log文件,其中包含多个具有相同变量名称的行,但我不需要所有这些,所以我要做的就是 从行:
“INC_MLIM = 074,ISO_MLIM = 074,LOC_LI_P = 050,LOC_LI_L = 050,TRI_LI_P = 074,TRI_LI_L = 074,”
使用较少的变量转换为新的线结构,并使用制表符而不是逗号分隔。新行看起来像这样:
“INC_MLIM = 074 ISO_MLIM = 074 LOC_LI_L = 050 TRI_LI_L = 074”
答案 0 :(得分:1)
您没有说明您想要的值。我会随意假设你想要INC_LIMI和INC_MLIM。
与大多数文本文件操作一样,这与纯批处理有关。但这是可能的。
我假设你的行都是< 8192个字符长。如果您的行数比那些长,那么就不可能使用纯批处理解决方案,您应该直接跳到本答案的底部以获取JREPL解决方案
批处理没有方便的拆分功能,允许拆分特定的用户定义字符。 FOR命令几乎可以正常工作,但它也会在;
,=
,<tab>
和<space>
分割。所以这不是一个好的选择。
使用正确的奥术语法,您可以使用变量扩展查找/替换来替换每个逗号的换行符(0x0A)。这将为每行生成一个name = value对,这非常方便让FINDSTR过滤掉你想要的值。
这是一个依赖临时表的解决方案。这会迭代所有* .log文件,对于每个文件,它会在* .log.new。
中创建输出@echo off
setlocal enableDelayedExpansion
(set LF=^
%= This creates a newline 0x0A character =%
)
for %%N in ("!LF!") do for %%F in (*.log) do (
(
for /f "usebackq delims=" %%A in ("%%F") do (
set "ln=%%A"
echo(!ln:,=%%~N!
)
)>"%%F.temp"
findstr /b "INC_LIMI= INC_MLIM=" "%%F.temp" >"%%F.new"
del "%%F.temp"
)
type *.log.new
exit /b
请注意,如果日志文件包含!
,则上述操作可能会失败。这可以通过根据需要打开和关闭延迟扩展来解决。
有些人不喜欢使用临时文件。在这种情况下,摆脱临时文件会引入更多神秘的批处理构造。但它确实消除了!
延迟扩展问题,并且代码更短。如果源文件非常大,这个版本也会明显变慢。
@echo off
setlocal disableDelayedExpansion
(set LF=^
%= This creates a newline 0x0A character =%
)
for %%F in (*.log) do (
for /f "usebackq delims=" %%A in ("%%F") do (
set "ln=%%A"
cmd /v:on /c "for %%N in ("!LF!") do @echo(!ln:,=%%~N!"|findstr /b "INC_LIMI= INC_MLIM="
)
) >"%%F.new"
type *.log.new
exit /b
也可以在不使用FINDSTR的情况下解决这个问题。但是这个解决方案假设在任何给定的行上都不会出现多次相同的名称,并且所有找到的名称都有一个值:
@echo off
setlocal disableDelayedExpansion
for %%F in (*.log) do (
for /f "usebackq delims=" %%A in ("%%F") do (
set "ln=,%%A"
for %%N in (INC_LIMI INC_MLIM) do call :findName %%N
)
) >"%%F.new"
type *.log.new
exit /b
:findName Name
setlocal enableDelayedExpansion
set "test=!ln!"
:loop
set "test2=!test:*,%1=!"
if "!test2!" equ "!test!" return
if not defined test2 return
if "!test2:~0,1!" neq "=" set "test=,!test2:*,=!" & goto :loop
for /f "delims=," %%V in ("!test2:~1!") do (
endlocal
echo(%1=%%V
)
exit /b
以下是处理空值的变体,但如果值包含引号或有毒字符,则可能会中断:
@echo off
setlocal disableDelayedExpansion
for %%F in (*.log) do (
for /f "usebackq delims=" %%A in ("%%F") do (
set "ln=,%%A"
for %%N in (INC_LIMI INC_MLIM) do call :findName %%N
)
) >"%%F.new"
type *.log.new
exit /b
:findName Name
setlocal enableDelayedExpansion
set "test=!ln!"
:loop
set "test2=!test:*,%1=!"
if "!test2!" equ "!test!" return
if not defined test2 return
if "!test2:~0,1!" neq "=" set "test=,!test2:*,=!" & goto :loop
set "test2=%1!test2!
endlocal&echo(%test2:,=&rem %
exit /b
但我不会使用上述任何一种。事实上,我绝不会将自己局限于纯粹的批处理,因为文本文件操作非常低效且难以理解。
相反,我会使用JREPL.BAT - a regular expression command line text processing utility。 JREPL.BAT是纯脚本(混合JScript /批处理),可以在任何Windows机器上从XP开始本地运行 - 不需要第三方exe文件。
使用JREPL,解决方案就像
一样简单@echo off
for %%F in (*.log) do call jrepl "(?:^|,)((?:INC_LIMI|INC_MLIM)=[^,]*)" "$txt=$1" /jmatchq /f "%%F" /o "%%F.new"
type *.log.new
代码不仅干净整洁,而且 比任何纯批处理解决方案都快。