我正在处理一个需要创建特定资源的项目,当创建资源时,我还会在文件中写入内容以便在出现错误时回滚该创建过程。但是这里有一个注意点,这些资源必须按与它们创建方式相反的方式进行删除,因此当我在回滚文件中编写如下内容时:
delete R1
delete R2
..
..
delete RN
我想按顺序删除资源 ->
delete RN
delete RN-1
....
...
delete R1
有没有一种方法可以在Windows批处理中实现这个功能?
我正在处理一个需要创建特定资源的项目,当创建资源时,我还会在文件中写入内容以便在出现错误时回滚该创建过程。但是这里有一个注意点,这些资源必须按与它们创建方式相反的方式进行删除,因此当我在回滚文件中编写如下内容时:
delete R1
delete R2
..
..
delete RN
delete RN
delete RN-1
....
...
delete R1
批处理中没有本地读取文件的方法来倒序读取。
但是,虽然不是最快的方法,可以通过按正常顺序读取文件,在每行前缀中添加填充数字,将列表按反向排序,拆分行以分隔数字,然后处理列表来解决这个问题。
@echo off
setlocal enableextensions disabledelayedexpansion
set "file=data.txt"
for /f "tokens=1,* delims=¬" %%a in ('
cmd /v:off /e /q /c"set "counter^=10000000" & for /f usebackq^ delims^=^ eol^= %%c in ("%file%") do (set /a "counter+^=1" & echo(¬%%c)"
^| sort /r
') do (
echo %%b
)
工作原理:
对于输入文件中的每一行,该代码将输出一个数字前缀和该行,使用分隔符(¬
)以便稍后能够分离这两个元素。
由于稍后数据将被排序,我们需要前缀具有统一的长度。因此,我们将计数器初始化为 10000000
,并递增,使所有行的前缀具有相同的长度(注意:如果您的文件有超过99999999行,请不要使用此方法)
要更改计数器,我们只需使用 set /a "counter+=1"
,但为了在循环内部回显它,我们需要延迟扩展,但这可能会对从文件中读取的数据产生问题(我不知道它是否可以包含 !
字符)。
我们可以启用/禁用延迟扩展来处理它,但由于这对于每一行都是必要的,因此将导致性能损失。为了解决这个问题,代码在单独的 cmd
实例中执行。
为什么要单独的实例?这个单独的实例中的代码不是在批处理上下文中执行的,而是在命令行上下文中执行的。在命令行上下文中,set /a
命令会回显计算结果,因此我们不需要这样做,并且延迟扩展问题消失了。我们只需计算新的计数器(它被回显),并回显从输入文件中读取的分隔符和行。因此,我们有以下代码:
set "counter=10000000"
for /f usebackq^ delims^=^ eol^= %%c in ("%file%") do (
set /a "counter+=1"
echo(¬%%c
)
这是一个连接命令,并作为参数传递给 cmd
实例(注意:使用^
来转义问题字符),然后使用echo off
(/q
)、启用扩展(/e
)和禁用延迟扩展(/v:off
)执行。
cmd /v:off /e /q /c"set "counter^=10000000" & for /f usebackq^ delims^=^ eol^= %%c in ("%file%") do (set /a "counter+^=1" & echo(¬%%c)"
这将生成带有前缀的输出。现在,要按相反顺序排序,需要将输出管道传递到 sort /r
命令。
cmd /c"..." | sort /r
由于管道需要进行处理(在本示例中我们仅将该行echo
到控制台上),完整的管道在for /f %%a
中执行(有更多的^
转义字符)。
for /f "tokens=1,* delims=¬" %%a in ('
cmd /c"..." ^| sort /r
') do ....
这个for
命令表示使用¬
字符作为分隔符来分割输入行(管道执行的结果),我们想要获取第一个标记(数字前缀,虽然不会用到但需要包含)存储在%%a
中,以及行的其余部分(没有额外的拆分)存储在%%b
中。
因此,在for /f %%a
的do
子句中的代码将按照反向顺序对输入文件中的每一行进行执行,并将该行存储在%%b
中。
这个程序可以将文件中的文本行反转。
交换
filter swap
将文件中的行反转,使顶部行变为底部行。
示例
cscript //nologo filter.vbs swap <"%systemroot%\win.ini"
从Filter.vbs来自https://skydrive.live.com/redir?resid=E2F0CE17A268A4FA!121 - 这里有19个用于处理文件中行的vbs程序示例。它还包括一个批处理文件,使其易于使用。
Set Arg = WScript.Arguments
set WshShell = createObject("Wscript.Shell")
Set Inp = WScript.Stdin
Set Outp = Wscript.Stdout
Dim LineCount
Set rs = CreateObject("ADODB.Recordset")
With rs
.Fields.Append "LineNumber", 4
.Fields.Append "Txt", 201, 5000
.Open
LineCount = 0
Do Until Inp.AtEndOfStream
LineCount = LineCount + 1
.AddNew
.Fields("LineNumber").value = LineCount
.Fields("Txt").value = Inp.readline
.UpDate
Loop
.Sort = "LineNumber DESC"
Do While not .EOF
Outp.writeline .Fields("Txt").Value
.MoveNext
Loop
End With
Del /F /Q "%Temp%\File.Sort.Reverse.txt" >Nul: 2>&1
SetLocal EnableDelayedExpansion
For /F %%a In ('Type "FileName" ^| Find /C /V ""') Do Set /A File.Lines.Count=%%a
Set /A File.Lines.Count+=1
For /F %%a In ('Type "FileName') Do Set /A File.Lines.Count-=1 & Set "File.Line.Number=00000000000000000000!File.Lines.Count!" & @Echo.[!File.Line.Number:~-20!]%%a>>"%Temp%\File.Sort.Reverse.txt"
EndLocal
For /F "Tokens=1* Delims=[]" %%a In ('Type "%Temp%\File.Sort.Reverse.txt" ^| Sort') Do Echo.%%b
delims=¬" %%a
中的¬
有什么用途?此外,您能否更详细地解释一下您的解决方案。 - Subham Tripathi¬
,因为我在我的键盘上找不到它 :) - Subham Tripathialt + 6
无效,不过我理解你的意思。 - Subham Tripathi