如何解决如何通过cmd用jrepl替换+追加?
在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
-
folder
不是C:\AAA
,而是C:\EEE\AAA
- 我必须更改{{1}中的文件的路径,用
list.txt
替换C:\AAA
,并且必须将C:\EEE\AAA
添加到该{{1}的每一行中}(因为错误,.jpg
及其子文件夹中的所有文件都具有该扩展名,例如list.txt
,C:\EEE\AAA
,...),然后再执行相同的操作。我希望这些更改位于新文件(image_1.jpg.jpg
)中,而不是原始的pdf_1.pdf.jpg
。
所以我添加了:
%newExcludeFile%
我这样做是为了从文件list.txt
中删除并创建文件set "newExcludeFile=C:\BBB\CCC\list_new.txt"
set "SEARCHTEXT=\AAA\"
set "REPLACETEXT=\EEE\AAA\"
%newExcludeFile%
现在,我缺少了在文件%excludeFile%
中每条记录的末尾添加if exist "%newExcludeFile%" del "%newExcludeFile%"
call jrepl "%sEARCHTEXT%" "%rEPLACETEXT%" /x /m /l /f "%excludeFile%" /o "%newExcludeFile%"
的部分,我在考虑是否有一种方法可以在不重复所有行的情况下进行操作取代。
解决方法
我建议您先阅读Stack Overflow页面,并提出以下问题:
How does the Windows Command Interpreter (CMD.EXE) parse scripts?
接下来,我发布该任务的简单解决方案,从输入文件C:\BBB\CCC\list_new.txt
创建输出文件C:\BBB\CCC\list.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 从文件
C:\BBB\CCC\list.txt
中读取另一行。 - 由于选项
delims=\
,使用反斜杠作为字符串定界符将每个非空行分成多个子字符串。 - 第一个子字符串是驱动器号和冒号,由于选项
tokens=2*
而被忽略,只是从行尾字符开始,在这种情况下,整行也将被忽略。 - 第一个子字符串始终为
C:
,因此在此用例中可以保留默认的eol=;
。没有行由于行尾字符而被忽略,因为没有行以分号开头,因此没有第一个子字符串以;
开头。 - 第二个子字符串在每行
AAA
上,并根据I
分配给指定的循环变量tokens=2
。 - 但是真正令人感兴趣的是每行上
C:\AAA\
之后的剩余部分,该部分没有根据*
之后的tokens=2
分配给下一行,而是循环变量{{1} }。
/F
的也可以使用 FOR 命令行:
J
此变体将驱动器号和冒号(第一个子字符串)从源文件复制到目标文件。
我是JREPL.BAT的粉丝,但是此批处理/ JScript混合对于此任务并不是真正必需的。
但是,这是使用(for /F "usebackq tokens=1,2* delims=\" %%I in ("%excludeFile%") do echo %%I\EEE\AAA\%%K.jpg)>"%newExcludeFile%"
的命令行与使用jrepl.bat
的命令行相同的功能。
for /F
它运行正则表达式搜索
- 字符串
call jrepl.bat "(\\AAA\\.*)$" "\EEE$1.jpg" /F "%excludeFile%" /O "%newExcludeFile%"
,其中每个反斜杠必须再转义一个反斜杠,因为反斜杠是搜索正则表达式中的转义字符,并且 - 用
\AAA\
表示0个或更多字符,直到行尾为止 - 在由
.*$
和(
定义的标记组中
将找到的每个字符串替换为
- 字符串
)
(JScript异常未转义反斜杠)和 - 使用
\EEE
反向引用找到的字符串来保留它,并且 - 附加了
$1
。
接下来,我想让所有答复的读者知道问题中张贴的批处理文件中几行编码不好的原因。
建议修改
.jpg
到
if "%rootPath:~-1%"=="\" (set rootPath= %rootPath:~0,-1%)
set localPath=%rootPath%\backup_deleted_media_%_date%
在这种情况下,针对字符串比较的命令 IF 的参数指定了100%正确的语法,这在我对Symbol equivalent to NEQ,LSS,GTR,etc. in Windows batch files的回答中对
- 第一个参数为第一个字符串
if "%rootPath:~-1%" == "\" set "rootPath=%rootPath:~0,-1%" set "localPath=%rootPath%\backup_deleted_media_%_date%"
; - 空格作为参数分隔符;
- 第二个参数是比较运算符
"%rootPath:~-1%"
; - 空格作为参数分隔符;
- 第三个参数是第二个字符串
==
。
在debugging the batch file上可以看到Windows命令处理器在执行命令 IF之前会自动纠正"\"
,其中if "%rootPath:~-1%"=="\"
到==
之间有空格。因此,最好在批处理文件中将字符串比较条件写成100%正确,并在if "%rootPath:~-1%" == "\"
周围加上空格。
在改进的命令行中,在命令 SET 的参数字符串中删除了==
的空格权,因为=
不应像前面详细描述的那样重新定义空格根据我对Why is no string output with 'echo %var%' after using 'set var = text' on command line?
两个 SET 命令的参数字符串另外包含在rootPath
中,以同样适用于包含与号字符的路径,否则path中的"
将被解释为AND运算符,以便在命令 SET 之后执行其他命令。有关&
的含义,请参见我在single line with multiple commands using Windows batch file上的答案,该含义不在双引号参数字符串中。
另请参阅我在syntax error in one of two almost-identical batch scripts: ")" cannot be processed syntactically here上的回答,该回答描述了几种非常常见的语法问题。 问题1 没有按照Windows命令处理器输出的帮助,将文件/文件夹参数字符串包含空格或这些字符之一&
的文件/文件夹参数字符串中的双引号引起来在命令提示符窗口中运行&()[]{}^=;!'+,`~
上。
两条命令行
cmd /?
例如,如果if not exist %localPath%\%%~pF md %localPath%\%%~pF
move %%F %localPath%\%%~pF
是用字符串localPath
定义的,那么也是很成问题的。
命令 IF 设计为在条件为true的情况下运行一个命令。如果只需要在真实条件下执行单个命令,则不应该使用C:\Temp\Test & Development
和(
,尽管始终可以仅使用一个命令来定义命令块。这是批处理文件编码中的第二种常见语法问题。
ASCII table中有很多字符,对于)
处理批处理文件及其内部命令 FOR 而言,它们没有特殊意义,但对于成批的初学者来说,文件编写倾向于使用小集合中的字符作为循环变量,它们具有特殊含义,例如cmd.exe
或a
,在用作循环变量时必须非常小心。
在成功执行F
之后,应始终使用命令popd
,特别是如果pushd
将具有UNC路径的网络资源访问权限分配给驱动器号时,尤其要使用该命令。否则,在重复执行批处理文件时可能会发生所有驱动器号最终都被使用。
最好使用可执行文件的标准文件名,以使批处理文件独立于环境变量pushd
和PATH
,并避免Windows命令对文件系统的不必要访问处理器来查找通常仅使用其文件名指定的文件,例如PATHEXT
或find
或findstr
。
以下是有问题的批处理文件代码,已修复了几乎所有小问题:
wmic
在大多数内部 FOR 循环中,@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
已更正为/C:"%excludeFile%"
。
注意:我从未测试过该批处理文件,因为我从未执行过该文件!
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。