删除某行及匹配行前后的行

Delete a certain line and lines before and after the matched line

在一个大的.ahk文件中,我需要在一行中找到文本'no label',删除之前的2行,之后的23行,并删除带有'no label'的行本身(总共 26 行)。文件中可以有多种情况,在所有情况下都需要删除这 26 行。

我不了解 SED、AWK 等,我需要在 windows 机器上 运行。使用 .bat 或其他 windows 应用程序是否可行,我可以 运行?

好的,接受挑战。这应该以 100% 形式执行您想要的操作。我发表了一些评论,但如果您有任何问题,请随时提出。

首先,它会扫描文件以查找 searchPhrase(当前为 "no label")的任何实例。如果找到,它会将行号保存为 refLine*。然后根据您的标准将上限设置为 refLine + 23,将下限设置为 refLine - 2。如果当前行号超出这些界限,它将把该行写入一个新的临时文件。完成后,它会备份原始文件,然后将其删除并重命名临时文件。

@echo off
setlocal enabledelayedexpansion
set "sourceFile=c:\temp\batchtest\myfile.txt"
set "tempFile=c:\temp\batchtest\tempfile.txt"
set "searchPhrase=no label"
set /a lineNum=0

REM check file for search phrase, store line as refLine
FOR /F "delims=" %%i IN (%sourceFile%) DO (
    set /a lineNum+=1
    echo !lineNum! = "%%i"
    if "%%i" == "%searchPhrase%" (
        echo Found "%searchPhrase%" on line !lineNum!
        set /a refLine=!lineNum!
    )
)

REM make backup
copy "%sourceFile%" "%sourceFile%-%DATE:/=-% %TIME::=-%.bak"

echo. 2>%tempFile%

REM Rewrite file 
set /a lineNum=0
    set /a lowEnd=%refLine%-2
    echo "Set low end to %lowEnd%"
    set /a highEnd=%refLine%+23
    echo "Set high end to %highEnd%"
FOR /F "delims=" %%i IN (%sourceFile%) DO (
    set /a lineNum+=1
    if !lineNum! GTR %lowEnd% (
        if !lineNum! LSS %highEnd% (
           echo "Skipping line #!lineNum!"
        )
    )
    if !lineNum! LSS %lowEnd% (
        echo "Writing Line !lineNum! %%i to temp file..."
        echo %%i >> %tempFile%
    )

    if !lineNum! GTR %highEnd% (
        echo "Writing Line !lineNum! %%i to temp file..."
        echo %%i >> %tempFile%
    )
)

REM get target filename only 
for %%F in ("%sourceFile%") do set fname=%%~nxF
REM del original file and rename tempfile
echo "Deleting original file..."
echo Y | del "%sourceFile%"
echo "Renaming %tempFile% to %fname%"
ren "%tempFile%" "%fname%"

*请注意,它目前只会找到 "no label" 的一个实例。如果您认为有多个实例,只需再次 运行 bat 文件即可。 如果有人愿意,他们可以找到多个实例并将行号存储到第三个临时文本文件中,然后使用它来确定更复杂的过滤范围。 或者,您可以将围绕整个事物循环并在找不到 searchPhrase.

的实例时退出循环
@ECHO OFF
SETLOCAL
SET "$="
SET "tempfile=%temp%\some-tempfile-name.txt"
ECHO.>"%tempfile%"
FOR /f "tokens=1*delims=:" %%a IN ('findstr /n /r ".*" q34397055.txt') DO (
 ECHO %%b|FIND "no label" >NUL
 IF NOT ERRORLEVEL 1 CALL :saveline# %%a
)
IF NOT DEFINED $ COPY /b q34397055.txt u:\newfile.txt 2>NUL >nul&GOTO done
(
FOR /f "tokens=1*delims=:" %%a IN ('findstr /n /r ".*" q34397055.txt^|findstr /v /b /g:"%tempfile%"') DO (
 ECHO(%%b
)
)>u:\newfile.txt
:done
DEL "%tempfile%"

GOTO :EOF

:saveline#
:: calculate START line number to delete
SET /a $=%1 - 2
:: number of lines to delete
SETLOCAL enabledelayedexpansion
FOR /l %%d IN (1,1,26) DO (
 >>"%tempfile%" ECHO(!$!:
 SET /a $+=1
)
GOTO :EOF

我使用了一个名为 q34397055.txt 的文件,其中包含一些测试数据。

产生 u:\newfile.txt

本质上,读取整个文件,以 line#:line content

格式对每一行进行编号

使用tokens工具提取行号部分,如果line-content部分包含目标字符串(不清楚OP是否想要一行containing "no label" 或者是否需要一行 完全匹配 "no label")然后调用 :saveline# 传递行号。

:saveline#中,计算出要删除的块的起始行,然后将要删除的行号以格式(例如)6:.. 32:.

然后执行相同的编号技巧,但这次过滤输出 包含 (/v) 在行的开头 (/b) 要删除的行号的临时文件中的任何字符串。

输出任何通过过滤器的行内容部分。

[编辑:修复空输出如果没有找到目标问题

插入 set "$=" 以确保变量 $ 在开头被删除。

插入if not defined $...行检测$是否成立(即:saveline#至少被调用一次)。如果:saveline#没有被调用,直接把源文件机械复制到目的地,然后跳到标签done删除临时文件。

插入标签done

建议:建立包含源文件名和目标文件名的变量,这样只需更改一次即可更改文件名,而不是两三个。 ]

@echo off
setlocal EnableDelayedExpansion

rem Get number of lines of sections to preserve in "copy.tmp" file
set last=0
(for /F "delims=:" %%a in ('findstr /N /C:"no label" input.ahk') do (
   set /A copy=%%a-3-last, last=copy+26
   echo !copy!
)) > copy.tmp


rem Read from input file
< input.ahk (

   rem Process all "copy-lines, skip-26" sections
   for /F %%n in (copy.tmp) do (
      for /L %%i in (1,1,%%n) do (
         set "line="
         set /P "line="
         echo(!line!
      )
      for /L %%i in (1,1,26) do set /P "line="
   )

   rem Copy the rest of lines after last section
   findstr "^"

) > output.ahk

del copy.tmp
move /Y output.ahk input.ahk