我正在寻找批处理文件在执行后将自身移动到已知位置的方法。自我移动 - 似乎是最恰当的名字,但我确信它有一个技术术语。我希望在所有其他代码运行后移动批处理文件。
move "C:\temp\move_me.bat" "D:\temp\move_me.bat"
其中move_me.bat是放在c:\ temp中的同名批处理文件,用于移动到d:\ temp。
我收到错误
找不到批处理文件。
即使批处理文件移动了位置。所以我有点困惑。我是否需要压制错误,或者最好是复制批处理文件并删除源代码?或者有更好的方法吗?
答案 0 :(得分:3)
Windows命令提示符cmd
不会将批处理文件缓存在内存中,而是通过行 1 从文件中读取它们。因此,只要move
命令完成,就会收到错误,因为无法再找到该文件。
您可以像这样调用批处理文件来抑制错误:
"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\
检查当前运行的批处理文件的位置;如果相等,批处理文件立即终止。
最后,原始批处理文件(由%~f0
2 访问)被复制(未移动)到新位置D:\temp
(文件名%~nx0
},仍然是一样的。)
下一行从新位置运行批处理文件,但不使用返回调用批处理脚本所需的call
,但这不是我们想要的。 &
operator允许下一个命令在前一个命令完成时执行。虽然未使用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"
> nul
portion会禁止显示消息(包括摘要1 file(s) copied.
)。 ||
operator仅在复制失败时执行下一个命令。因此,当执行原始批处理文件时,将按预期完成复制。当复制的批处理文件运行时,copy
会尝试将批处理文件复制到自身上,这会导致消息The file cannot be copied onto itself.
(由> nul
抑制)并且会在错误中触发{{1}命令(由于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"
相比,if
查询是必要的,与move
相反,如果源和目标相等,则不会返回错误。
这是一个批处理文件的综合解决方案,它可以自动移动并在之后控制移动的文件。查看所有解释性说明,找出哪个代码由哪个批处理文件实例运行:
copy
1)请注意,带括号的代码块@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
/ (
和续行)
被视为一个命令行:
( echo This entire parenthesised block is echo considered as a single command line. ) echo This continued line & ^ echo as well.
2)请注意,一旦读取并解析了命令行或块,就会立即解析此类参数引用,因此在实际执行之前。
答案 1 :(得分:0)
批处理文件是逐行执行的,而不是一次性读入内存。在move
命令之后还有其他命令吗?
但是,批处理文件还具有调用另一个批处理文件将覆盖批处理文件的功能。
所以,你可能能够逃脱:
if "%1" == "continuation" goto :continuation
REM interesting things go here
move "C:\Temp\move_me.bat" "D:\Temp\move_me.bat"
"D:\Temp\move_me.bat" continuation
:continuation
REM more interesting things go here
或者将批处理文件复制到目的地,然后继续删除原始副本。
或让您的批处理文件将其自身复制到目标(并自行删除)作为第一个事物。这可能更容易理解。