Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Batch file 如何使用批处理脚本更改文件中的行顺序?_Batch File_For Loop - Fatal编程技术网

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

Batch file 如何使用批处理脚本更改文件中的行顺序?,batch-file,for-loop,Batch File,For Loop,A有一个包含dir结果的文本文件 dir "%local%" /b /a:d /s >> FolderList.txt 但是我想在一个循环中迭代,从最后一行到第一行 由于我认为这不能在For命令中完成,因此如何生成包含相同行但顺序相反的新文件?您不能使用For命令。但是您可以使用dir“%local%”/o-n/b/a:d/s>>FolderList.txt,颠倒创建文本文件的dir列表的顺序;-表示“反转”。您不能使用For命令。但是您可以使用dir“%local%”/o-n/b

A有一个包含dir结果的文本文件

dir "%local%" /b /a:d /s >> FolderList.txt
但是我想在一个
循环中迭代,从最后一行到第一行


由于我认为这不能在
For
命令中完成,因此如何生成包含相同行但顺序相反的新文件?

您不能使用
For
命令。但是您可以使用
dir“%local%”/o-n/b/a:d/s>>FolderList.txt,颠倒创建文本文件的
dir
列表的顺序;
-
表示“反转”。

您不能使用
For
命令。但是您可以使用
dir“%local%”/o-n/b/a:d/s>>FolderList.txt,颠倒创建文本文件的
dir
列表的顺序;
-
表示“已反转”。

目的是重新排列文件夹列表,以防止在按顺序删除文件夹时出现问题

我提出了以下算法。我接受建议,使其更有效率或更好

@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
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

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

@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

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

@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 MB时有效,因为这是批处理变量的限制

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

但是

如果您想以自下而上的顺序删除文件夹的所有树内容,“正确”的方法是通过递归子例程

编辑回答dbenham

正如我在回答中所说,我提出的两种方法可以修改,以正确处理特殊字符和空行。在我的回答中,我展示了一种按相反顺序“更改行顺序”的通用方法,但没有特别注意创建输出文件,因为OP在自己的回答中说,“目的是重新排列文件夹列表,以防止在按顺序删除文件夹时出现问题”,所以我认为这足以向他展示如何以相反的顺序处理文件夹。我还假设文件夹列表:

  • 没有感叹号(!)
  • 没有前导冒号(:)
  • 文件夹名称小于4096字节
  • 少于1000000行
  • 没有空行
我甚至认为(现在仍然认为)OP想要用来删除文件夹列表的方法是不够的,我在一个大的下提到了这一点,但是在我的回答中建议使用递归子程序

然而dbenham似乎认为最初的问题类似于“什么是按相反顺序对大型文件进行排序的最有效方法?”并批评我的方法,因为它们缺乏此类功能。因此,我应该回答这个新问题(有效方法),对吗

首先,我觉得有趣的是,dbenham批评我的方法是因为“实际上并没有提供所要求的解决方案(实际的文件输出)”,但在他自己修改的解决方案2中,他写道“这是我最喜欢的解决方案,因为直接在变量中处理文件可能会消除文件输出,从而完全避免创建任何临时文件”

dbenham提出的两种方法在效率方面有一个严重的问题,在中已经讨论过:对
setlocal EnableDelayedExpansion
endlocal
命令在文件的每一行都执行。如果文件很大(如前一个问题所述,即200000行,大约8MB)环境将被复制到一个新的内存区域,然后被删除,这将重复200000次!当然,这项任务非常耗时。在dbenham的修改后的解决方案2中,这个问题会变得更糟:随着行处理的进行,环境在该点存储文件内容时会增长。在文件的最后一行中几乎等于整个文件大小的环境会将文件的每一行复制到一个新的内存区域。当然,这是实现此过程效率方面最差的方法

还有另一种处理空行和特殊字符的方法,不需要
setlocal EnableDelayedExpansion-endlocal
对。有关此方法的详细信息以及关于处理大型文件的有效方法的进一步讨论,请参阅前面提到的问题

以下批处理文件是我对“如何以高效的方式对大文件进行反向排序”的修改版本

修改的解决方案1:使用带有排序的临时文件

@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
您可以使用
MEM/p
命令检查环境内存块的大小和位置。在旧MS-DOS(command.com)中将环境放置在command.com之后的天数,但如果将常驻程序放置在环境之后,则该程序将无法再增长。因此,command.com中提供了/E:nnnnn开关,以便为环境保留以字节为单位的特定大小

今天剩下的时间我没有时间检查这个方法,但它在这里
@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%
@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%*"
@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%