如何通过cmd用jrepl替换+追加?

How to replace + append with jrepl via cmd?

在Windows中,我有一个用于处理文本文件C:\BBB\CCC\list.txt的批处理文件,用于决定移动哪些文件。它应该移动文件夹 (%folder%) 及其子文件夹中的所有文件,但前提是:

在那 list.txt 我有数百万行,例如:

C:\AAA\XXX\ZZZ\image_1.jpg
C:\AAA\XXX\KKK\image_2.jpg
C:\AAA\XXX\ZZZ\pdf_1.pdf

这是批处理文件,它可以很好地用于此目的:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "folder=C:\AAA"
set "excludeFile=C:\BBB\CCC\list.txt"
set /p excludeName="Year not to delete: "
echo:
set /p rootPath="Backup folder path: " 
FOR /f %%a in ('WMIC OS GET LocalDateTime ^| find "."') DO Set _DTS=%%a
Set _date=%_DTS:~0,4%%_DTS:~4,2%%_DTS:~6,2%

if "%rootPath:~-1%"=="\" (set rootPath= %rootPath:~0,-1%)

set localPath=%rootPath%\backup_deleted_media_%_date%
echo:
rem // Change to the root directory:
pushd "%folder%" && (
    rem // Loop through all files but exclude those listed in the list file:

    for /F "delims= eol=|" %%F in ('
    dir /B /S /A:-D "*.*" ^| findstr /V /L /I /X /G:"%excludeFile%"') do (
        for /D %%I in ("%%F\..") do (

            echo.%%~nxI|findstr /C:"%excludeFile%" >nul 2>&1
            if not errorlevel 1 (
                echo Found
            ) else (
                if not exist %localPath%\%%~pF md %localPath%\%%~pF
                move %%F %localPath%\%%~pF

            )
        )
    )
)
rem // Return from currently iterated directory to root directory:
endlocal

cmd /k

我现在需要的是另一个批处理文件来做大致相同的事情但是:

所以我添加了:

set "newExcludeFile=C:\BBB\CCC\list_new.txt"
set "SEARCHTEXT=\AAA\"
set "REPLACETEXT=\EEE\AAA\"

我这样做是为了从文件 %excludeFile%

中删除和创建文件 %newExcludeFile%
if exist "%newExcludeFile%" del "%newExcludeFile%"
call jrepl "%SEARCHTEXT%" "%REPLACETEXT%" /x /m /l /f "%excludeFile%" /o "%newExcludeFile%"

现在我错过了在文件 %newExcludeFile% 中每条记录的末尾附加 .jpg 的部分,我在想是否有一种方法可以在不迭代所有行的情况下做到这一点在那之后再次更换。

我建议先阅读带有问题的 Stack Overflow 页面:
How does the Windows Command Interpreter (CMD.EXE) parse scripts?

我 post 接下来是从输入文件 C:\BBB\CCC\list.txt 创建输出文件 C:\BBB\CCC\list_new.txt 的任务的简单解决方案,将每行开头的 C:\AAA 替换为 C:\EEE\AAA 并在每行末尾追加 .jpg 以便 C:\BBB\CCC\list.txt

中的行
C:\AAA\XXX\ZZZ\image_1.jpg
C:\AAA\XXX\KKK\image_2.jpg
C:\AAA\XXX\ZZZ\pdf_1.pdf

进入文件C:\BBB\CCC\list_new.txt

C:\EEE\AAA\XXX\ZZZ\image_1.jpg.jpg
C:\EEE\AAA\XXX\KKK\image_2.jpg.jpg
C:\EEE\AAA\XXX\ZZZ\pdf_1.pdf.jpg

此任务可以通过以下方式完成:

@echo off
set "excludeFile=C:\BBB\CCC\list.txt"
set "newExcludeFile=C:\BBB\CCC\list_new.txt"
(for /F "usebackq tokens=2* delims=\" %%I in ("%excludeFile%") do echo C:\EEE\AAA\%%J.jpg)>"%newExcludeFile%"

真的就这些了。

  • FOR 选项 /F 从文件 C:\BBB\CCC\list.txt.
  • 一行接一行地读取
  • 由于选项 delims=\.
  • ,每个非空行都使用反斜杠作为字符串分隔符拆分为子字符串
  • 第一个子字符串是驱动器号和冒号,由于选项 tokens=2* 而被忽略,但以行尾字符开头的情况除外,在这种情况下,整行也会被忽略。
  • 第一个子字符串始终是 C:,因此在此用例中可以保留默认值 eol=;。没有因为行尾字符而忽略的行,因为没有以分号开头的行,因此没有以 ;.
  • 开头的第一个子字符串
  • 根据tokens=2.
  • 分配给指定循环变量I的每一行AAA上的第二个子字符串
  • 但真正感兴趣的是每一行 C:\AAA\ 之后的剩余部分,根据 tokens=2 之后的 * 分配给下一个循环变量 J.

也可以使用FOR命令行:

(for /F "usebackq tokens=1,2* delims=\" %%I in ("%excludeFile%") do echo %%I\EEE\AAA\%%K.jpg)>"%newExcludeFile%"

此变体将驱动器号和冒号(第一个子字符串)从源文件复制到目标文件。

我是 JREPL.BAT 的粉丝,但是这个 batch/JScript 混合体并不是这个任务所必需的。
但是,这里使用 jrepl.bat 的命令行与使用 for /F.

的命令行执行相同的操作
call jrepl.bat "(\AAA\.*)$" "\EEE.jpg" /F "%excludeFile%" /O "%newExcludeFile%"

它运行是一个正则表达式搜索

  • 字符串 \AAA\ 每个反斜杠必须用一个反斜杠进行转义,因为反斜杠是搜索正则表达式中的转义字符并且
  • with .*$ 0 个或更多字符到行尾
  • 在用 ()
  • 定义的标记组中

替换每个找到的字符串
  • 字符串\EEE(反斜杠未被 JScript 异常转义)和
  • </code> 找到的字符串进行反向引用以保留它并且 </li> <li>附加了 <code>.jpg

接下来我想让这个答案的所有读者知道在批处理文件的几行中编码不好的地方post在问题中给出了原因。

建议修改

if "%rootPath:~-1%"=="\" (set rootPath= %rootPath:~0,-1%)

set localPath=%rootPath%\backup_deleted_media_%_date%

if "%rootPath:~-1%" == "\" set "rootPath=%rootPath:~0,-1%"

set "localPath=%rootPath%\backup_deleted_media_%_date%"

命令 IF 的参数在这种情况下使用 100% 正确的字符串比较语法指定,正如我在 和 [=88 上的回答中广泛描述的那样=]

  • 第一个参数第一个字符串 "%rootPath:~-1%";
  • space 作为参数分隔符;
  • 第二个参数比较运算符 ==;
  • space 作为参数分隔符;
  • 第三个参数第二个字符串 "\".

上可以看到,Windows命令处理器会自动更正if "%rootPath:~-1%"=="\"==到[=54=之间缺少spaces ] 在执行命令 IF 之前 spaces。因此最好在批处理文件中用 ==.

左右 spaces 写入字符串比较条件 100% 正确

= 的 space 权利在命令 SET 的参数字符串中被删除,因为 rootPath 不应被重新定义正如我在 Why is no string output with 'echo %var%' after using 'set var = text' on command line?

上的回答所详细描述的那样,开头有一个 space

两个 SET 命令的参数字符串另外包含在 " 中,以便也适用于包含 & 字符的路径,否则 & 在路径中将被解释为在命令 SET 之后执行的附加命令的 AND 运算符。请参阅我在 single line with multiple commands using Windows batch file 上的回答,了解 & 的含义,它不在双引号参数字符串中。

另请参阅我在 上的回答,其中描述了几种非常常见的语法 问题 问题 1 未按照 file/folder 包含 space 或这些字符之一 [=61] 的要求将 file/folder 参数字符串括在双引号中=] 如 Windows 命令处理器在命令提示符 window.

上 运行 上 cmd /? 输出的帮助所描述

两个命令行

if not exist %localPath%\%%~pF md %localPath%\%%~pF
move %%F %localPath%\%%~pF 

也很成问题,如果 localPath 例如用字符串 C:\Temp\Test & Development 定义。


指令IF被设计为运行一个条件为真的指令。如果只需要在 true 条件下执行单个命令,则不应使用 (),尽管总是可以只用一个命令定义一个命令块。这是关于批处理文件编码的第二个常见语法问题


ASCII table 中有很多字符对于 cmd.exe 处理批处理文件及其内部命令 FOR 都没有特殊意义,但是批处理文件编写的初学者倾向于使用小集合中的字符作为循环变量,这些字符具有特殊含义,如 aF 必须非常小心地用作循环变量。


在成功执行pushd 之后,应始终使用命令popd,尤其是当pushd 将具有UNC 路径的网络资源访问分配给驱动器号时。否则在重复执行批处理文件时可能会发生所有盘符最终都被使用的情况。


最好尽可能使用可执行文件的完全限定文件名来使批处理文件独立于环境变量 PATHPATHEXT 并避免不必要的文件系统访问Windows 命令处理器查找通常仅使用其文件名指定的文件,例如 findfindstrwmic.


这里是 post 有问题的批处理文件代码,修复了或多或少的小问题:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "folder=C:\AAA"
set "excludeFile=C:\BBB\CCC\list.txt"
set /P "excludeName=Year not to delete: "
echo:
set /P "rootPath=Backup folder path: "
for /F %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime ^| %SystemRoot%\System32\find.exe "."') do set "_DTS=%%I"
set "_date=%_DTS:~0,4%%_DTS:~4,2%%_DTS:~6,2%"

if "%rootPath:~-1%" == "\" set "rootPath=%rootPath:~0,-1%"

set "localPath=%rootPath%\backup_deleted_media_%_date%"
echo:
rem // Change to the root directory:
pushd "%folder%" && (
    rem // Loop through all files but exclude those listed in the list file:

    for /F "eol=| delims=" %%I in ('dir /B /S /A:-D "*.*" ^| %SystemRoot%\System32\findstr.exe /V /L /I /X /G:"%excludeFile%"') do (
        for /D %%J in ("%%I\..") do (

            echo.%%~nxJ|%SystemRoot%\System32\findstr.exe /C:"%excludeName%" >nul
            if errorlevel 1 (
                if not exist "%localPath%\%%~pI" md "%localPath%\%%~pI"
                move "%%I" "%localPath%\%%~pI"
            ) else echo Found
        )
    )
    popd
)
rem // Return from currently iterated directory to root directory:
endlocal

%ComSpec% /K

在最内部的FOR循环中,/C:"%excludeFile%"被额外修正为/C:"%excludeName%"

注意:这个批处理文件没有经过我测试,因为我从来没有执行过它!