批处理文件:从日志文件中读取最后一行并将它们复制到一个新文件中

Batchfile: read last lines from logfiles and copy them to a new file

这是我的第一篇文章,所以如果格式不符合预期,请原谅。 (

的建议

欢迎改进。)

我正在尝试创建一个批处理文件,它将从日志文件中读取最后几行并将它们复制到一个新文件中。

到目前为止,我已经找到 here 阅读最后一行的方法。

代码类似于:

for /f %%i in ('find /v /c "" ^< someFile.txt') do set /a lines=%%i
set /a startLine=%lines% - 1
more /e +%startLine% someFile.txt > lastLines.txt

以上代码一次适用于一个文件。我需要的是从已知列表中的所有文件中读取最后一行,并将这一行添加到新的 .csv 文件中。

我一直在使用以下代码获取日志文件中的第 4 个条目,但它 returns 每个日志文件的每一行:

for /f %%x in (%list%) do for /f "delims=.txt,  tokens=4" %%i in (%%x.txt) do echo %%x, %%i >> output.csv

我需要的是两者的组合,但我不知道如何组合它们并将完整的最后一行复制到 .csv 文件。

=== @马古: 感谢您的反应。 在每个日志文件中可以有 1 到 >100 行以逗号分隔的信息。类似于:

"LOGON,6-1-2015,12:43:39,USERNAME,HOSTNAME,,,,192.168.209.242,00:21:5A:2E:64:5E" 

第 4 个条目的最后一个代码用于获取已登录计算机的所有帐户的列表。此代码为我提供了一个非常大的列表,其中包含我在 %list% 中检查的所有计算机日志中的所有 logon/logoff 事件。 在 %list$ 中,我有我想要检查的所有日志文件的名称。这返回了所有行。

对于新的批处理文件,我只需要最后一个 logon/logoff 条目并且我想要整个最后一行。

所以我有一个 .txt 文件,其中包含我需要检查的所有计算机的主机名。 将通过变量 %list%.

逐行读取此 .txt 文件。

我只需要将每个日志文件的最后一行复制到输出文件。

=== 我刚刚尝试了 JosefZ 提供的解决方案。不幸的是,这对我还不起作用。没有最后一行被复制到结果文件中。在代码中,我删除了可能的最后一行的额外条目,因为日志中没有空行,我还为我希望在结果中可用的主机名添加了一个条目。 JosefZ 在那里有文件名:

@ECHO OFF >NUL
@SETLOCAL enableextensions disabledelayedexpansion    
type nul>output.csv    
set "list=_listing.txt"
for /F "tokens=*" %%x in ('type "%list%"') do (
  set "host=%%~x" 
  for /F "tokens=*" %%G in ('type "%%~x"') do set "lastline=%%G"
  call :lline
)    
:endlocal
@ENDLOCAL
goto :eof    
:lline    
  set "filename=.\logs\%filename:&=^&%.txt"
  echo %host%,%lastline%>>output.csv
goto :eof

结果文件仅显示主机名。我会用这个来解决更多问题,但欢迎所有提示!

=== 明白了!!!

@ECHO OFF >NUL
@SETLOCAL enableextensions disabledelayedexpansion

type nul>output.csv

set "list=_listing.txt"
for /F "tokens=*" %%x in ('type "%list%"') do (
  set filename=   :: *empty previous filename*
  set lastline=   :: *empty previous lastline* 
  set "host=%%~x" 
  set "filename=.\logs\%host%.txt"  :: *creating the filename from path+hostname+extention*
  for /F "tokens=*" %%G in ('type "%filename%"') do set "lastline=%%G"
  call :lline
)

:endlocal
@ENDLOCAL
goto :eof

:lline

  echo %host%,%lastline%>>output.csv

goto :eof

如果文件有更多尾随空行,您的行编号方法可能会失败。幸运的是 for /F 循环忽略(不迭代)空行;让我们开始使用这个功能:在脚本中使用接下来的做法:

  • disabledelayedexpansion 允许在文件名中使用 !
  • set "list=_listing.txt" 其中 _listing.txt 包含文件名列表(包括完整路径和扩展名 .txt),一行一个文件名:由 dir /b /s *.txt>_listing.txt[ 获取=50=]
  • type nul>files\output.csv 清空输出文件(可选)
  • set "lastline=!!!file empty!!!"初始化变量%lastline%;也可以是 set "lastline="
  • call :lline 处理变量 %filename%%lastline%
  • set "filename=%filename:&=^&%" 允许在文件名中使用 &

脚本如下:

@ECHO OFF >NUL
@SETLOCAL enableextensions disabledelayedexpansion
type nul>files\output.csv

set "list=_listing.txt"
for /F "tokens=*" %%x in ('type "%list%"') do (
  set "filename=%%~x"
  set "lastline=!!!file empty!!!"

  rem the whole line
  for /F "tokens=*" %%G in ('type "%%~x"') do set "lastline=%%G"

  rem the fourth token only
  rem for /F "tokens=4" %%G in ('type "%%~x"') do set "lastline=%%G"

  call :lline
)
:endlocal
@ENDLOCAL
goto :eof

:lline
  set "filename=%filename:&=^&%"
  echo %filename% %lastline%
  rem >>files\output.csv
goto :eof

示例 _listing.txt 文件:

d:\bat\filesexclam!ation.txt
d:\bat\filesexc!lam!ation.txt
d:\bat\filesper%cent.txt
d:\bat\filesper%cent%.txt
d:\bat\filesper%Gcent.txt
d:\bat\filesper%%Gcent.txt
d:\bat\filesampers&nd.txt
d:\bat\filesampers&&nd.txt

输出:

d:\bat>lastlines
d:\bat\filesexclam!ation.txt 0 15.01.2015  1:52:28.48 -15072 20465
d:\bat\filesexc!lam!ation.txt 6 15.01.2015  1:52:28.50 3250 16741
d:\bat\filesper%cent.txt -8 15.01.2015  1:52:28.50 -3692 27910
d:\bat\filesper%cent%.txt !!!file empty!!!
d:\bat\filesper%Gcent.txt 0 15.01.2015  1:52:28.56 14508 12374
d:\bat\filesper%%Gcent.txt 1 15.01.2015  1:52:28.56 30540 26959
d:\bat\filesampers&nd.txt 15.01.2015  1:22:50.18
d:\bat\filesampers&&nd.txt 15.01.2015  1:22:50.18

老实说,所有这些压舱物都是(可能)用于文件中的尾随空行和(可能)仅用于文件名中的 !&;一切都可以用

完成
for /f %%x in (%list%) do for /f "skip=%startLine% tokens=4" %%i in (%%x) do echo %%x, %%i >> output.csv

您应该使用简单的 FOR 来迭代值列表,而不是 FOR /F。

像下面这样的东西应该可以工作:

@echo off
setlocal enableDelayedExpansion
>>output.csv (
  for %%F in (
    "file1.log"
    "file2.log"
    "file3.log"
    etc.
  ) do (
    for /f %%A in ('find /v /c "" <%%F') do set /a skip=%%A-1
    more +!skip! %%F
  )
)

文件名周围有引号,以防您得到带空格的名称。

你可以使用你的 LIST 变量,如果它看起来像
set LIST="file1.log" "file2.log" "file3.log" etc.

@echo off
setlocal enableDelayedExpansion
set LIST="file1.log" "file2.log" "file3.log" etc.    
>>output.csv (
  for %%F in (%LIST%) do (
    for /f %%A in ('find /v /c "" <%%F') do set /a skip=%%A-1
    more +!skip! %%F
  )
)

如果您的任何文件名包含 ! 字符,那么您必须在循环中打开和关闭延迟扩展。否则延迟扩展会在扩展 %%F 时破坏名称。

@echo off
setlocal disableDelayedExpansion
set LIST="file1.log" "file2.log" "file3.log" etc.    
>>output.csv (
  for %%F in (%LIST%) do (
    for /f %%A in ('find /v /c "" <%%F') do set /a skip=%%A-1
    setlocal enableDelayedExpansion
    more +!skip! %%F
    endlocal
  )
)