【问题标题】:Self-moving batch file自移动批处理文件
【发布时间】:2017-08-09 05:24:53
【问题描述】:

我正在寻找一种让批处理文件在执行后将自身移动到已知位置的方法。自动移动 - 似乎是最贴切的名称,但我敢肯定它有一个技术术语。我想在所有其他代码运行之后移动批处理文件。

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

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

我得到了错误

找不到批处理文件。

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

【问题讨论】:

    标签: windows batch-file


    【解决方案1】:

    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\ 检查当前运行的批处理文件的位置;如果相等,则批处理文件立即终止。

    最后,原始批处理文件(由%~f02访问)被复制(未移动)到新位置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 命令的错误(由于@987654352 @) 离开批处理文件,因此不会尝试执行最后一行。


    您也可以使用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 查询是必要的,因为 movecopy 不同,如果源和目标相等,则不会返回错误。


    这里是一个批处理文件的综合解决方案,它可以自行移动并在之后控制被移动的文件。看看所有的解释性注释,找出哪个批处理文件实例运行了哪些代码:

    @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) 请注意,带括号的代码块(/) 和后续行^ 被视为单个命令行:

    (
        echo 这个带括号的整个块是
        echo 被视为单个命令行。
    )
    echo 这条续行 & ^
    echo 也是。

    2) 请注意,此类参数引用会在读取和解析命令行或块后立即解析,因此在实际执行之前。

    【讨论】:

      【解决方案2】:

      批处理文件是逐行执行的,而不是一次性读入内存。 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
      

      或者将您的批处理文件复制到目标位置,然后继续删除原始副本。

      或者让您的批处理文件将自己复制到目标(并删除自己),作为它所做的第一个操作。这可能更容易理解。

      【讨论】:

      • move 之后的行我想将不再被识别。也许您可以将move 更改为copy 并在:continuation 部分中删除del 的原始批处理文件...
      • ...或保留move,但只需用& 连接下一行,那么它应该被识别...
      猜你喜欢
      • 2019-07-13
      • 2015-09-28
      • 2012-03-08
      • 2016-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-30
      • 1970-01-01
      相关资源
      最近更新 更多