The Windows command prompt cmd
does not cache batch files in memory, it reads them from the file line by line1. Therefore you receive an error as soon as the move
command has been finished, because the file cannot be found any more.
您可以像这样调用批处理文件来抑制错误:
"C:\temp\move_me.bat" 2> nul
但这也无意中抑制了所有其他错误消息。
不管怎样,也许下面的方法适合你——这是脚本C:\temp\move_me.bat
:
if /I "%~dp0"=="D:\temp\" exit /B
rem // (some other code here...)
copy "%~f0" "D:\temp\%~nx0"
"D:\temp\%~nx0" & del "%~f0"
首先,检查当前运行的批处理文件的位置D:\temp\
;如果相等,则立即终止批处理文件。
Finally, the original batch file (accessed by %~f0 http://ss64.com/nt/syntax-args.html2) is copied (not moved) to the new location D:\temp
(the file name, %~nx0 http://ss64.com/nt/syntax-args.html, remains the same).
下一行从新位置运行批处理文件,但不使用call http://ss64.com/nt/call.html,需要返回到调用批处理脚本,但这不是我们想要的。这让前一个命令完成后执行下一个命令。虽然call
未使用,下一个命令仍会执行,因为整行已被读取并解析cmd
。但执行控制现在位于批处理文件的新实例,因此错误消息The batch file cannot be found.
不再出现。
之前所提if
查询立即退出批处理文件副本的执行,因此其其他代码不会运行两次。
如果您不想跳过复制的批处理文件的执行,请删除if
命令行并修改copy
命令行来获取这个:
rem // (some other code here...)
copy "%~f0" "D:\temp\%~nx0" > nul || exit /B
"D:\temp\%~nx0" & del "%~f0"
The > nul portion http://ss64.com/nt/syntax-redirection.html抑制显示消息(包括摘要1 file(s) copied.
). The ||操作员 http://ss64.com/nt/syntax-redirection.html仅当复制失败时才执行下一个命令。因此,当执行原始批处理文件时,复制将按预期完成。当复制的批处理文件运行时,copy
尝试将批处理文件复制到自身上,这会导致消息The file cannot be copied onto itself.
(被抑制> nul
)并且在触发的错误中exit /B
命令(由于||
) 离开批处理文件,因此不会尝试执行最后一行。
您也可以使用以下方法实现相同的行为move
;所以相关代码如下所示:
if /I "%~dp0"=="D:\temp\" exit /B
rem // (some other code here...)
move "%~f0" "D:\temp\%~nx0" & "D:\temp\%~nx0"
或者,如果您希望移动的脚本不跳过其他代码:
rem // (some other code here...)
if /I not "%~dp0"=="D:\temp\" move "%~f0" "D:\temp\%~nx0" & "D:\temp\%~nx0"
The if
查询是必要的,因为move
,与copy
,如果源和目标相等,则不会返回错误。
这是批处理文件的综合解决方案,它可以自行移动并随后对移动的文件进行控制。查看所有说明性注释,了解哪些批处理文件实例运行哪些代码:
@echo off
rem // Define constants here:
set "_TARGET=D:%~pnx0" & rem /* (this defines the movement destination;
rem in your situation, the original batch file is
rem `C:\temp\move_me.bat`, so the target file is
rem `D:\temp\move_me.bat` (only drive changes)) */
rem // (code that runs for both batch file instances...)
echo Batch file: "%~f0"
echo [executed by both files before the movement check]
rem // Check whether current batch file is the moved one:
if /I "%~f0"=="%_TARGET%" (
rem // (code that runs for the moved batch file instance only...)
echo Batch file: "%~f0"
echo [executed only by the moved file]
) else (
rem // (code than runs for the original batch file instance only...)
echo Batch file: "%~f0"
echo [executed only by the original file]
rem // Actually move the batch file here, then give control to the moved one:
> nul move "%~f0" "%_TARGET%"
"%_TARGET%"
rem /* (code that runs for the original batch file instance only;
rem this is run after the moved batch file has finished;
rem you must not use `goto` herein as the target label cannot be found,
rem because the original file does no longer exist at this point!) */
echo Batch file: "%~f0"
echo [executed only by the original file, but after the moved one has finished]
)
rem // (code that runs for the moved batch file instance only...)
echo Batch file: "%~f0"
echo [executed only by the moved file after the movement check]
exit /B
1) Note that parenthesised blocks of code (
/)
and continued lines ^
are considered as a single command line:
(
echo This entire parenthesised block is
echo considered as a single command line.
)
echo This continued line & ^
echo as well.
2) Note that such argument references are immediately resolved as soon as a command line or block is read and parsed, hence before it is actually executed.