我为我的家用计算机制作了这个脚本,以便轻松地将所有照片和视频集备份到一个外部硬盘驱动器。
SET BackUpDir=%~d0BackUpDir
for %%d in (C: D:) do (
if exist %%d (
robocopy %%d %BackUpDir% *.jpg *.jpeg *.dng *.nef *.mp4 *.mov *.wmv *.avi *.3gp *.3g2 /MIN:20000 /MAX:2703622144 /s /W:15 /XD C:$WINDOWS.~BT "C:System Volume Information" C:Windows "C:Program Files" C:Boot C:MSOCache C:Recovery "C:Program Files (x86)" "C:Documents and Settings" C:ProgramData "C:UsersAll Users" C:UsersDefault "C:UsersDefault User" C:Usersdefaultuser0 C:UsersPublic )
)
exit 0
我有几台具有不同分区结构的计算机。其中一个只有驱动器C:
和D:
,但例如第二个有五个分区。
现在我有这行代码,只在两个分区上查找文件:
for %%d in (C: D:) do (
我不想每次都编辑脚本以添加其他分区,例如在第一台计算机上不存在,但在第二台计算机上确实存在。我希望我的脚本自动找到计算机上的所有可用分区,除了执行备份脚本的外部硬盘驱动器。
如何更改上面的命令行以实现这一目标?
我想要这样的东西:
for %%d in ("list of all partition" except "backup external hard drive") do (
您已经知道如何获取要排除的驱动器,它位于第一行,%~d0
,因为您正在使用它来设置要备份到的目录。
此外,您可以使用exist
找出实际存在的驱动器。
因此,以下脚本将处理所有存在的驱动器,这些驱动器与运行脚本的驱动器不匹配:
@echo off
rem Expand following list as needed.
for %%d in (C D E F G H I J) do (
if exist %%d:. if not %%d:==%~d0 (
echo Processing drive %%d
)
)
当我从具有C:
驱动器,空D:
DVD和E:
SSD的系统上的驱动器C:
运行它时,我得到:
Processing drive E
我建议使用以下代码:
@echo off
set "BackUpDir=%~d0BackUpDir"
for /F "skip=1" %%I in ('%SystemRoot%System32wbemwmic.exe LOGICALDISK where DriveType^=3 GET DeviceID') do (
if /I not "%~d0" == "%%I" %SystemRoot%System32robocopy.exe %%I %BackUpDir% *.jpg *.jpeg *.dng *.nef *.mp4 *.mov *.wmv *.avi *.3gp *.3g2 /MIN:20000 /MAX:2703622144 /s /W:15 /XD C:$WINDOWS.~BT "C:System Volume Information" C:Windows "C:Program Files" C:Boot C:MSOCache C:Recovery "C:Program Files (x86)" "C:Documents and Settings" C:ProgramData "C:UsersAll Users" C:UsersDefault "C:UsersDefault User" C:Usersdefaultuser0 C:UsersPublic
)
Windows Management Instrumentation CommandWMIC用于访问Win32_LogicalDisk类的信息。感兴趣的数据是带有冒号的驱动器号存储在属性DeviceID
中。
当前连接的所有逻辑磁盘都将使用命令行输出:
%SystemRoot%System32wbemwmic.exe LOGICALDISK GET DeviceID
输出例如:
DeviceID
C:
D:
E:
F:
Q:
R:
S:
有一个标题行,每个逻辑磁盘包含DeviceID
和下一行。所有行都有尾随空格。输出文本是 UTF-16 小端序(每个字符两个字节)而不是 ANSI(每个字符一个字节)编码。
但备份任务感兴趣的只是本地磁盘。因此,命令行被修改为:
%SystemRoot%System32wbemwmic.exe LOGICALDISK GET DeviceID,DriveType
例如,带有尾随空格的 Unicode 编码输出现在为:
DeviceID DriveType
C: 3
D: 3
E: 3
F: 3
Q: 5
R: 5
S: 2
好的,输出驱动器号与驱动器类型信息。根据Win32_LogicalDisk类的文档,3
类型的驱动器对于备份操作Microsoft感兴趣。
可以使用IF条件过滤FOR循环中的行。但wmic.exe
还提供了使用where
的过滤器可能性。因此,可以使用命令行按wmic.exe
直接过滤驱动器列表:
%SystemRoot%System32wbemwmic.exe LOGICALDISK where DriveType=3 GET DeviceID
例如,带有尾随空格的 UTF-16 LE 编码输出是:
DeviceID
C:
D:
E:
F:
这是使用FOR循环处理的输出,如上面的批处理文件代码所做的那样。
在这种情况下,带有选项/F
的FOR在后台启动一个新的命令进程,并在圆括号内附加%ComSpec% /c
和两个'
之间的命令行,导致 Windows 在执行时安装到C:Windows
:
C:WindowsSystem32cmd.exe /c C:WindowsSystem32wbemwmic.exe LOGICALDISK where DriveType=3 GET DeviceID
等号=
不是用双引号括起来的参数字符串的一部分。因此,cmd.exe
处理批处理文件会将字符=
解释为参数分隔符,如空格、制表符或逗号,并在执行命令FOR之前将=
替换为空格字符。因此,由后台启动的单独命令进程执行的命令行将使用where DriveType 3
而不是where DriveType=3
,这将是where
子句的无效语法。因此,在执行命令FOR之前,必须对等号进行转义,^
cmd.exe
解析整个FOR命令行及其命令块时将其解释为文字字符。
FOR捕获所有输出以处理已启动命令进程的STDOUT,并在启动cmd.exe
终止自身后逐行处理捕获的文本。
FOR在处理捕获的输出时始终忽略空行。
默认情况下,FOR使用普通空格和水平制表符作为分隔符将每行拆分为子字符串,并仅将第一个空格/制表符分隔的字符串分配给指定的循环变量I
。这正是这里需要的行处理行为。
默认情况下,FOR也会忽略所有以分号开头的行,因为eol=;
是行尾选项的默认值。此处不得更改行尾选项,因为要处理的所有行都以驱动器号开头。
实际上,FOR首先使用指定或默认的字符串分隔符拆分行,然后检查第一个子字符串是否以指定或默认的行尾字符开头。因此,在这种情况下,FOR也会忽略例如以一个或多个前导空格/制表符开头的行,并且下一个字符;
。但这不会在这里发生,因此可以保留FOR的默认行尾选项。
但是第一条带有DeviceID
的输出线并不感兴趣。在处理FOR捕获的输出时,可以使用包含在"
中的选项skip=1
跳过此行。
备份驱动器上很可能不需要附加条件if /I not "%~d0" == "%%I"
是驱动器类型为2
的可移动磁盘。但是,还可以使用此代码将除备份驱动器以外的所有本地驱动器备份到备份驱动器(也是本地驱动器)。