Windows 如何在批处理文件的for循环中展开两个局部变量
我正在尝试编写一个脚本,它应该从文件列表中读取并按照相同的结构将每个项目复制到新位置 最初,这是为了复制在Git提交范围内更改的文件,但由于我找到了一种更简单的方法(首先是C#“脚本”),现在我只是为了学习而这样做 这是文件_list.txt的一个示例: 这是迄今为止我的.bat文件:Windows 如何在批处理文件的for循环中展开两个局部变量,windows,loops,batch-file,for-loop,Windows,Loops,Batch File,For Loop,我正在尝试编写一个脚本,它应该从文件列表中读取并按照相同的结构将每个项目复制到新位置 最初,这是为了复制在Git提交范围内更改的文件,但由于我找到了一种更简单的方法(首先是C#“脚本”),现在我只是为了学习而这样做 这是文件_list.txt的一个示例: 这是迄今为止我的.bat文件: @echo关闭 延迟扩展 设置“源=输入目录” 设置“目标=输出目录” 对于(“file_list.txt”)中的/f“tokens=*usebackq”%%A,请执行以下操作( 设置“文件=%%A” 设置“目
@echo关闭
延迟扩展
设置“源=输入目录”
设置“目标=输出目录”
对于(“file_list.txt”)中的/f“tokens=*usebackq”%%A,请执行以下操作(
设置“文件=%%A”
设置“目标文件已满=%target%\!文件:%source%=!”
设置“dest\u file\u filename=%%~nxA”
::设置dest\u file\u dir=(!dest\u file\u full-!dest\u file\u filename)
如果不存在“!dest\u file\u dir!”(
md“!目标文件目录!”
)
设置“源文件已满=%source%\!文件:%source%=!”
复制“!源文件已满!”!目标文件目录!”
)
暂停
注意注释行set dest\u file\u dir=(!dest\u file\u full-!dest\u file\u filename)
。这是伪代码。我需要在这里使用变量替换,但cmd.exe不会一步扩展两个局部变量
我已经试过烟斗了
echo set dest\u file\u dir=^!目标文件已满:!目标文件名!=^!|指令
或使用调用:
调用set dest\u file\u dir=!!目标文件已满:!dest_file_filename!=!!
但两者都不起作用
我在这些方面做错了什么,或者有没有一种优雅的方法(因此不使用临时文件)来实现这一点
谢谢
FOR %%y IN ("!dest_file_full!") DO set "dest_file_dir=%%~dpy"
应该将目标驱动器+路径+终端\
放入dest\u file\u dir
毋庸置疑,注释的:
形式不应该在块中使用
应该将目标驱动器+路径+终端\
放入dest\u file\u dir
毋庸置疑,注释的:
形式不应该在块中使用。在(代码块)中的字符串操作有时会令人困惑。我个人更喜欢将其放入sub。此批次暂时关闭提示并打开Echo,以便更好地输出您的更改:
@echo off
setlocal enabledelayedexpansion
Set MyPrompt=%Prompt%
Prompt $S
Echo on
set "source=input dir"
set "target=output dir"
for /f "tokens=* usebackq" %%A in ("file_list.txt") do call :sub "%%A"
pause
Prompt %MyPrompt%
Goto :Eof
:Sub
set "FILE=%~1"
set "dest_file_full=%target%\!FILE:%target%=!"
set "dest_file_filename=%~nx1"
set "dest_file_dir=!dest_file_full:%dest_file_filename%=!"
Rem if not exist "%dest_file_dir%" md "%!dest_file_dir%"
set "source_file_full=%source%\%FILE%"
@Echo copy "%source_file_full%" "%dest_file_dir%"
特别是第二组对我来说不清楚,更真实的变量应该会有所帮助。在(代码块)中的字符串操作有时会令人困惑。我个人更喜欢将其放入sub。此批次暂时关闭提示并打开Echo,以便更好地输出您的更改:
@echo off
setlocal enabledelayedexpansion
Set MyPrompt=%Prompt%
Prompt $S
Echo on
set "source=input dir"
set "target=output dir"
for /f "tokens=* usebackq" %%A in ("file_list.txt") do call :sub "%%A"
pause
Prompt %MyPrompt%
Goto :Eof
:Sub
set "FILE=%~1"
set "dest_file_full=%target%\!FILE:%target%=!"
set "dest_file_filename=%~nx1"
set "dest_file_dir=!dest_file_full:%dest_file_filename%=!"
Rem if not exist "%dest_file_dir%" md "%!dest_file_dir%"
set "source_file_full=%source%\%FILE%"
@Echo copy "%source_file_full%" "%dest_file_dir%"
特别是第二组对我来说不清楚,更多的实数变量应该会有所帮助。这个答案只阐述了扩展“嵌套变量”:
简而言之,使用以下命令:
call set "dest_file_dir=%%dest_file_full:!dest_file_filename!=%%"
转义^编码>或使用调用和代码>无法使用延迟扩展来扩展嵌套变量
管道也帮不上忙,因为它们为双方初始化了新的cmd
实例,它们使用各自独立的环境
让我们先看看使用立即展开的嵌套变量:
call set "dest_file_dir=%%dest_file_full:%dest_file_filename%=%%"
call
引入第二个解析阶段,这是解析嵌套所必需的。call
命令接收一个部分扩展的命令行,如下所示(例如,假设%dest\u file\u filename%
扩展为config.php
):
这只是具有立即扩展的正常子字符串替换语法,它在所述第二解析阶段被扩展
注意:如果dest_file_filename
的值以%
、~
或*
开头(但这是文件名的禁止字符),或者如果它包含=
,则此方法将失败!此外,如果存在,“
也可能会引起问题(但在文件名中也不允许出现这种情况)
现在,让我们看看一种类似的方法,但启用了延迟扩展:
根据帖子,call
引入了第二个解析阶段,但这不包括延迟扩展,而只包括立即扩展;因此延迟扩展只在第一个解析阶段进行
与上面使用即时扩展的解决方案类似,我们需要确保子字符串替换语法的搜索和替换字符串在第一个解析阶段被扩展,并且整个表达式由第二个解析阶段处理;因此,让我们使用以下方法:
call set "dest_file_dir=%%dest_file_full:!dest_file_filename!=%%"
因此,调用
命令接收以下部分扩展的命令行:
set "dest_file_dir=%dest_file_full:config.php=%"
同样,这构成了具有立即扩展的子字符串替换语法
注意:如果dest_file_filename
的值以%
、~
或*
开头(但这是文件名的禁止字符),或者如果它包含=
,则此方法将失败。此外,如果存在,“
也可能会导致问题(但在文件名中也不允许这样做)
引入扩展嵌套变量所需的第二个解析阶段的另一种方法是使用for
循环,如下所示:
for /F delims^=^ eol^= %%K in ("!dest_file_filename!") do set "dest_file_dir=!dest_file_full:%%K=!"
这里,!dest_file_filename!
在解析整个for/F
循环时展开;第二个解析阶段应用于循环体,并接收dest_file_filename
(例如,config.php
)的值,而不是%K
此方法的优点是完全避免了立即扩展,如果dest_file_filename
的值中出现“
,则可能会导致问题;但是,这会导致!
和^
出现问题(需要通过前面的^
来避免这些问题)。
dest\u file\u filename
的值不能以~
或*
开头,也不能包含=
for /F delims^=^ eol^= %%K in ("!dest_file_filename!") do set "dest_file_dir=!dest_file_full:%%K=!"