如何更改使用批处理脚本文件中的行的顺序?

一个有一个包含目录的结果的文本文件

dir "%local%" /b /a:d /s >> FolderList.txt

但是,我想在一个迭代For循环从最后要到第一线。

因为我相信这能不能做到在For命令,我怎么能生成包含同样的思路,但在相反的顺序一个新的文件?

--------------解决方案-------------

您无法使用For命令。 但是你可以颠倒顺序dir创建文本文件列表,使用dir "%local%" /on /b /a:d /s >> FolderList.txt ; 的-意思是“逆转”。

我都喜欢Aacini的原方案的总体战略,但他们写的有问题(一些琐碎,有些显著)

原来Aacini解决方案1使用临时文件与排序:

  • 包含感叹号腐化线(!)
  • 条主导结肠(多个)(:)从每个线
  • 使用临时文件的创建>>不如>高效
  • 使用4096字节的默认排序行的最大长度
  • 线100万计数上限不必要
  • 实际上并没有提供要求的解决方案(实际的文件输出)
  • 叶一个临时文件

修改液1

下面是解决问题的一个版本。 唯一的实际限制是8180字节(字符)的最大行长度。 我不知道怎么FINDSTR高可以算,但这种解决方案可以处理多达999个十亿行。(我同意Aacini,没有人会希望等待这样一个大的文件使用批处理的解决方案来完成)的行限制可以很容易地进行调整。

@echo off
setlocal DisableDelayedExpansion
set file="%~1"
set revfile="%~1.rev"
set tempfile="%temp%\revfile%random%.txt"
(
for /f "delims=" %%a in ('findstr /n "^" %file%') do (
set "ln=%%a"
setlocal EnableDelayedExpansion
for /f "delims=:" %%n in ("!ln!") do set "prefix=000000000000%%n"
echo !prefix:~-12!!ln:*:=!
endlocal
)
)>%tempfile%
(
for /f "delims=" %%a in ('sort /rec 8192 /r %tempfile%') do (
set "ln=%%a"
setlocal EnableDelayedExpansion
echo(!ln:~12!
endlocal
)
)>%revfile%
del %tempfile%

Aacini修改的方案1

Aacini通过SET / P和多个TEMP文件显着改善的鲁棒性和性能与改进的溶液1。 在SET / p解决方案消除了一个环形SETLOCAL / ENDLOCAL切换的需要,但它确实有一些限制。

  • 行必须终止<LF><CR>正常为Windows,但Unix上的风格是在Windows世界中有时会遇到)。
  • 行必须<= 1024个字符
  • 在行尾控制字符将被剥离。

修改的方案1走2

如果上述任何限制是一个问题,下面是使用多个临时文件我的第一解决方案的适应。 像Aacinis修改的方案,它的文件大小线性执行。 它是较慢的约40%,比Aacinis修改版本。

@echo off
setlocal DisableDelayedExpansion
set file="%~1"
set revfile="%~1.rev"
set "tempfile=%temp%\revfile%random%.txt"
findstr /n "^" %file% >"%tempfile%.1"
(
for /f "usebackq delims=" %%a in ("%tempfile%.1") do (
set "ln=%%a"
setlocal EnableDelayedExpansion
for /f "delims=:" %%n in ("!ln!") do set "prefix=000000000000%%n"
echo !prefix:~-12!!ln:*:=!
endlocal
)
)>"%tempfile%.2"
sort /rec 8192 /r "%tempfile%.2" >"%tempfile%.3"
(
for /f "usebackq delims=" %%a in ("%tempfile%.3") do (
set "ln=%%a"
setlocal EnableDelayedExpansion
echo(!ln:~12!
endlocal
)
)>%revfile%
del "%tempfile%*"

原来Aacini溶液2使用环境变量:

  • 包含感叹号腐化线(!)
  • 带空行
  • 实际上并没有提供要求的解决方案(实际的文件输出)

修改液2

下面是解决问题的一个版本。 已知的唯一限制是

  • 8181和8190之间的最大行长度取决于行号
  • 略低于64MB的最大文件大小。

是我最喜欢的解决方案,因为该文件输出也许可以通过直接处理变量中的文件,从而彻底避免任何临时文件的创建。基于Aacini提供信息编辑但是被淘汰,我了解到它有严重的性能问题,因为环境的发展。 问题是不如Aacini实现- 即使是一个简单的SET命令有大尺寸的环境遭受极大我已经张贴关于这种现象在DosTips问题 http://www.dostips.com/forum/viewtopic.php?f= 3&T = 2597(我最初发布的SO,但显然这个问题太过开放式的为这个网站)

@echo off
setlocal disableDelayedExpansion
set file="%~1"
set revfile="%~1.rev"
set num=0
for /f "delims=" %%a in ('findstr /n "^" %file%') do (
set /a "num+=1"
set "ln=%%a"
setlocal enableDelayedExpansion
for %%n in (!num!) do for /f "delims=" %%b in (""!ln:*:^=!"") do endlocal&set "ln%%n=%%~b"'
)
setlocal enableDelayedExpansion
(
for /l %%n in (!num! -1 1) do echo(!ln%%n!
)>%revfile%

有两种比较简单的方法以按相反的顺序文件。 第一个是在文件内容的直接方法:添加行号的所有行,排序以相反的顺序文件,消除行号:

@echo off
setlocal EnableDelayedExpansion
rem Insert line numbers in all lines
for /F "tokens=1* delims=:" %%a in ('findstr /n ^^ %1') do (
set /A lineNo=1000000+%%a
echo !lineNo!:%%b>> tempfile.txt
)
rem Sort the file and show the result
for /F "tokens=1* delims=:" %%a in ('sort /r tempfile.txt') do (
echo Line %%a is %%b
)

另一种方法包括在加载文件行批阵列,可以在你希望的任何方式进行处理:

@echo off
setlocal EnableDelayedExpansion
rem Load file lines in a Batch array
set lineNo=0
for /F "delims=" %%a in (%1) do (
set /A lineNo+=1
set "line[!lineNo!]=%%a"
)
rem Process array elements in reversed order:
for /L %%i in (%lineNo%,-1,1) do (
echo Line %%i is !line[%%i]!
)

这最后的方法的工作仅在文件的尺寸低于64兆,因为这是为批次变量的极限。

这两种方法都可以修改,以正确地处理特殊字符(> <|)。

然而

如果你想删除自下而上的顺序选择文件夹的所有内容的树,“正确”的方式做到这一点是通过一个递归子程序...

编辑 答案为dbenham

正如我在答复中写道,我提出了两种方法可以修改,以正确处理特殊字符和空行。 在我的答案我发现“改变行的顺序”以相反的顺序支付没有特别的关注,因为OP在他自己的答案说, 创建一个输出文件 一般方法是“我们的目标是重新排列的文件夹,以防止问题的列表而在序列“删除他们,所以我认为这是足以表明他如何处理以相反的顺序的文件夹。 我还假设文件夹列表:

  • 没有感叹号(!)。
  • 没有领导冒号(:)。
  • 文件夹名称大于4096字节的短。
  • 少超过100万行。
  • 没有空行。

我甚至想(和仍然认为)的OP要用来删除文件夹的列表的方法是不够的,我然而,在我的答复中提到下一个大这一点上提出使用递归子程序来代替。

然而似乎dbenham认为原来的问题是类似的东西“什么是最有效的方法以按相反的顺序一个大的文件?” 和批评我的方法,因为它们缺少这种功能。 出于这个原因,我应该在这个新的问题(有效的方法),右侧方面答复?

排在首位,这很有趣,我认为dbenham critizice我的方法,因为“实际上并没有提供要求的解决方案(实际的文件输出)”,但在他自己修改的方案2,他写道:“这是因为我最喜欢的解决方案文件输出大概可以通过处理在直接变量文件,从而完全避免了任何临时文件的创建“被消除。 ???

通过dbenham提出的两个方法有一个已经在这个问题上讨论的效率方面的一个严重问题:一对setlocal EnableDelayedExpansionendlocal 命令该文件的每一行执行。 如果该文件是大(即200 000线和大约8 MB,如前面提到的问题)的环境将被复制到新的存储区域,然后被删除,并且这将重复20万次! 当然,这个任务是耗时。 这个问题成为dbenham的修改解决方案2更糟:由于行处理下去,环境成长,因为它保存该文件的内容在这一点上。 在该文件的最后几行几乎等于整个文件的大小的环境将被复制到新的存储区的文件的每一个剩余的行 。 当然,这是实现在效率方面这个过程中,最糟糕的方式!

还有另一种方式来处理空行和特殊字符不要求setlocal EnableDelayedExpansion - endlocal对。 有关此方法和有效的方式来处理大文件的进一步讨论,请参见前面提到的问题。

下面的批处理文件是关于“如何排序以高效的方式在相反的顺序一个大文件”我的修改版本。

修改解决方案1:SORT使用临时文件

@echo off
setlocal EnableDelayedExpansion
set revfile="%~1.rev"
set tempfile=%temp%\revfile%random%

rem Insert line numbers in all lines
findstr /n ^^ %1 > "%tempfile%1.txt"
find /c ":" < "%tempfile%1.txt" > "%tempfile%2.txt"
set /P lines=< "%tempfile%2.txt"
call :JustifyLineNumbers < "%tempfile%1.txt" > "%tempfile%2.txt"
del "%tempfile%1.txt"

rem Sort the file in reversed order
sort /rec 8192 /r "%tempfile%2.txt" /o "%tempfile%3.txt"
del "%tempfile%2.txt"

rem Remove line numbers
call :RemoveLineNumbers < "%tempfile%3.txt" > %revfile%
del "%tempfile%3.txt"
goto :EOF

:JustifyLineNumbers
for /L %%i in (1,1,%lines%) do (
set /A lineNo=1000000000+%%i
set /P line=
echo !lineNo!!line:*:=!
)
exit /B

:RemoveLineNumbers
for /L %%i in (1,1,%lines%) do (
set /P line=
echo !line:~10!
)
exit /B

这个解决方案仍然有“才”1147483647线(最高32位的签署正整数减去初始种子)的限制。 虽然这种限制可以通过dbenham提出的方法很容易地增加,该修改意味着较慢的执行速度。 结论是:如果真的想反向排序非常大的文件不要使用批处理文件,但更高效的编程语言(如C)。

修改解决方案2:使用批处理变量数组

@echo off
setlocal EnableDelayedExpansion
set revfile="%~1.rev"
set tempfile=%temp%\revfile%random%

rem Load file lines in a Batch array
findstr /n ^^ %1 > "%tempfile%1.txt"
find /c ":" < "%tempfile%1.txt" > "%tempfile%2.txt"
set /P lines=< "%tempfile%2.txt"
del "%tempfile%2.txt"
call :CreateArray < "%tempfile%1.txt"
del "%tempfile%1.txt"

rem Process array elements in reversed order:
(for /L %%i in (%lines%,-1,1) do echo=!ln%%i!) > %revfile%
goto :EOF

:CreateArray
for /L %%i in (1,1,%lines%) do (
set /P line=
set ln%%i=!line:*:=!
)
exit /B

编辑大环境问题的一个可能的解决方案

我设计可以解决一个想法,至少部分,造成非常大的环境SET命令的性能问题。 让我们假设内部运作SET VAR=VALUE命令请按照下列步骤操作:

  • 当一个新的变量与超过当前环境大小的值定义,环境被复制到一个新的领域,如果超越它的区域不可用。
  • 新的区域只是大到足以接受新的变量。 没有额外的保留空间。
  • 最重要的一项:当一个大的变量被删除,剩余的可用空间不会被释放。 环境内存块永远不会缩水。

如果前面的步骤是真实的,那么性能问题可能会降低,如果我们首先通过大(8 KB)变量与工作变量同名保留所需的环境空间。 例如,要预留1024 KB我们定义了128大变数; 我想,以限定这些128变量所需要的时间将小于用较短变量填补同一1024的KB所需的时间。

当过程运行时,第一个128个作业变量的定义将采取必要的时间,以删除一个8KB的变量和定义一个较短的,但是对于在处理的变量129必须更快,因为它只是限定在一个新的可变一个已经可用的空间。 为了有助于此过程中,变量必须具有将它们放置在环境的末端作为dbenham指示名字。

:ReserveEnvSpace sizeInKB
rem Define the first large variable (reserving 6 bytes for variable name)
rem (this method may be done in larger chunks until achieve the fastest one)
set z1=X
for /L %%i in (1,1,8184) do set z1=!z1!X
rem Define the rest of large variables
set /A lastVar=%1 / 8
for /L %%i in (2,1,%lastVar%) do set z%%i=!z1!
exit /B

您可以使用MEM /P命令检查环境内存块的大小和位置。 在旧的MS-DOS(command.com)天环境放在command.com后,但如果驻留程序放置后的环境,那么它不能再生长。 出于这个原因,在/ E:NNNNN开关在command.com提供给对环境字节预留一定大小。

我没有时间来检查这个方法的一天的休息,但在这里它是为你!

其目的是要重新排列的文件夹的列表防止出现问题,而在顺序删除它们。

我想出了下面的算法。 我接受建议,使之更有效率或更高。

@ECHO off
setLocal EnableDelayedExpansion

:: File that contains a list of folders
set file_from=%~1

:: Destination file, that will contain the sorted list
if "%2"=="" (
set replace=1
set file_to=_%file_from%
) else (
set file_to=%~2
)
:: Create empty destination file
if exist "%file_to%" del "%file_to%"
copy NUL "%file_to%"

:: Temporary file
if exist ".\~Remaining.txt" del ".\~Remaining.txt"
copy "%file_from%" .\~Remaining.txt

:: Sort the order of folders

:while
set untouched=1
For /f "tokens=* delims=" %%a in (.\~Remaining.txt) Do (
:: check if line was already added
FindSTR /X /C:%%a "%file_to%"
if errorlevel 1 (
set untouched=0
:: check if folder contains sub-folders to be added
FindSTR /B /C:%%a\ .\~Remaining.txt
if errorlevel 1 (
:: remove current line from "~Remaining.txt"
FindSTR /V /B /E /C:%%a .\~Remaining.txt> .\~Remaining_new.txt
move .\~Remaining_new.txt .\~Remaining.txt
:: add current line to destination file
>> "%file_to%" ECHO %%a
goto while
)
)
)
if untouched LSS 1 (
goto while
)

if exist .\~Remaining.txt del .\~Remaining.txt

if defined replace (
ECHO REPLACE!
:: destination was not provided, so replace
if exist "%file_from%" del "%file_from%"
move "%file_to%" "%file_from%"
)

此代码将扭转一个文本文件,但有一些限制。 空行被省略,含有特殊的字符行导致失败:&<> |

@Echo Off
If "%1"=="" Goto Syntax
If "%2"=="" Goto Syntax
If Not Exist %1 (
Echo File not found: %1
Exit /B 2
)
SetLocal EnableDelayedExpansion
Set SOF=~StartOfFile~
Set InFile=%~snx1~in
Set OutFile=%2
Set TempFile=%~snx1~temp
If Exist %OutFile% Del %OutFile%
If Exist %TempFile% Del %TempFile%
Copy %1 %InFile% >nul
:Loop
Set "Line=%SOF%"
For /F "tokens=*" %%a In (%InFile%) Do (
If Not "!Line!"=="%SOF%" Echo !Line!>>%TempFile%
Set "Line=%%a"
)
Echo %Line%>>%OutFile%
Del %InFile%
If Not Exist %TempFile% (
EndLocal
Exit /B 0
)
Rename %TempFile% %InFile%
Goto Loop

:Syntax
Echo Usage:
Echo %~n0 input-file output-file
Echo.
Exit /B 1

分类:批处理文件 时间:2015-03-14 人气:0
本文关键词: 批处理文件,for循环
分享到:

相关文章

Copyright (C) 55228885.com, All Rights Reserved.

55228885 版权所有 京ICP备15002868号

processed in 1.252 (s). 10 q(s)