删除某行及匹配行前后的行
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% batch-file 形式执行您想要的操作。我发表了一些评论,但如果您有任何问题,请随时提出。
首先,它会扫描文件以查找 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
在一个大的.ahk文件中,我需要在一行中找到文本'no label',删除之前的2行,之后的23行,并删除带有'no label'的行本身(总共 26 行)。文件中可以有多种情况,在所有情况下都需要删除这 26 行。
我不了解 SED、AWK 等,我需要在 windows 机器上 运行。使用 .bat 或其他 windows 应用程序是否可行,我可以 运行?
好的,接受挑战。这应该以 100% batch-file 形式执行您想要的操作。我发表了一些评论,但如果您有任何问题,请随时提出。
首先,它会扫描文件以查找 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