2017-03-17 129 views
1

我正在寻找批处理文件在执行后将其自身移动到已知位置的方法。自我移动 - 似乎是最恰当的名字,但我确信有一个技术术语。我想在所有其他代码都运行后移动批处理文件自动移动批处理文件

move "C:\temp\move_me.bat" "D:\temp\move_me.bat" 

其中move_me.bat是放在c:\ temp中的同名批处理文件,将其移动到d:\ temp。

我得到的错误

The batch file cannot be found.

即使批处理文件移动位置。所以我有点困惑。我需要抑制错误还是最好复制批处理文件并删除源文件?或者有更好的方法来做到这一点?

回答

3

Windows命令提示符cmd不会在内存中缓存不批处理文件,它通过线从文件中读取行他们。因此,只要move命令完成,您将收到错误,因为无法再找到该文件。

你可以这样调用批处理文件来取消错误:

"C:\temp\move_me.bat" 2> nul 

但这supresses所有其他错误消息也无意的。

无论如何,或许下面的方法对你的作品 - 这是脚本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 访问)被复制(不是移动)到新位置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抑制),并且出现一个错误,该错误会触发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,如果源和目标相等,则不返回错误。


下面是一个批处理文件的全面解决方案,该文件自动移动并对移动的文件进行控制。看看所有的解释性说明,找出哪些代码是由什么批处理文件实例上运行:

@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)注意parenthesised (/)并继续行^的代码块被认为是单个命令行:

(
    echo This entire parenthesised block is 
    echo considered as a single command line. 
) 
echo This continued line &^
echo as well.

2)注意,这样的参数的引用被立即尽快解析为一个命令线O r块被读取和解析,因此在它被实际执行之前。

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 

或者副本您的批处理文件复制到目标,并有延续删除原始副本。

或者让你的批处理文件自己复制到目的地(并删除它自己),作为第一个的事情。这可能更容易理解。

+0

'move'后面的行不再被识别,我想。也许你可以在':continuation'部分把'move'改成'copy'并用'del'删除原来的批处理文件...... – aschipfl

+0

...或者保留'move',但是简单地用'&'连接下一行' ,那么应该认识到... – aschipfl