前景提要
在服务器日常维护工作中,因为用户或者同事要批量导出附件用作数据分析或者工作汇报,会提供一个文件列表,文件列表里面的附件不在同一个目录,并且也不会完全复制同一个目录下面的所有文件。不同于网上其他的从一个目录批量复制文件到另一个目录,本文章讲的是通过遍历列表,按需复制文件到指定目录。
附件列表格式
这里举个例子说一下附件列表的形式,是一个txt文件,在这里就叫1.txt吧,链接已经过脱敏处理,所以看起来会很怪。
K:/dcsgs/ppy/051zz/01zzfile/axcazppy2cgbgzz.file
K:/dcsgs/kk/axc222az/ppy02-20071730/051zz/01zzfile/azcv2.file
K:/dcsgs/kk/axc222az/ppy02-20071730/051zz/01zzfile/azcv22.file
K:/dcsgs/s2fhg/vew3baz/ppy/051zz/01zzfile/vew3bazdf32cv2.file
K:/dcsgs/s2fhg/vew3baz/ppy/051zz/01zzfile/vew3bazdf32cv21.file
K:/aa/s2fhg/vew3baz/ppy/051zz/02asfile/01ppy2cgbgfv232cgbg/083dvgf3.file
K:/aa/s2fhg/vew3baz/ppy/051zz/02asfile/01ppy2cgbgfv232cgbg/073dvgf2cgbgfv23.file
K:/aa/s2fhg/vew3baz/ppy/051zz/02asfile/01ppy2cgbgfv232cgbg/03df32file.file
K:/aa/s2fhg/vew3baz/ppy/051zz/02asfile/01ppy2cgbgfv232cgbg/01qq.file
K:/aa/s2fhg/vew3baz/ppy/051zz/02asfile/02as/01CAD/17dc2.file
K:/qdv/s2fhg/vew3baz/ppy/051zz/02asfile/02as/01CAD/1412cppy.file
K:/qdv/s2fhg/vew3baz/ppy/051zz/032file/01a/043dvgfss4.10.file
I:/ds/a12f/a12f2az/ppy/051zz/032ffile/28qdsf/01CAD/13242.file
I:/ds/a12f/a12f2az/ppy/051zz/032ffile/28qdsf/01CAD/11.file
I:/ds/a12f/a12f2az/ppy/051zz/032ffile/28qdsf/01CAD/121.file
I:/ds/a12f/a12f2az/ppy/051zz/02asfile/01ppy2cgbgfv232cgbg/d.file
I:/ds/a12f/a12f2az/ppy/051zz/02asfile/01ppy2cgbgfv232cgbg/11.file
I:/ds/a12f/a12f2az/ppy/051zz/02asfile/02as/02file/a.file
每一个都列清楚了文件所处位置,每个文件夹里面只取指定文件,其他都不取出,总体分为K盘和I盘,是两个盘。
之前的写法
我手里有几个其他同事写的脚本,在Windows Server 2008环境下使用的非常顺。
这些CMD脚本分两种思路,一种是遍历附件列表1.txt,进行for循环处理;一种是通过excel处理附件列表,批量生成每个文件的复制命令。第二种太不程序员了,这里只说第一种。
@echo off
for /f "delims=" %%a in ('type "1.txt"') do "C:\Windows\System32\xcopy.exe" "%%a" "F:\20211111\i\%%~pa" /s /y
pause
直接用xcopy复制,并用%%a获取文件名,%%~pa获取文件掐头去尾的路径。
注意这里%%~pa,除了p是获得路径,目前已知n,x,d都有自己的功能,可以试一下。
做这个的时候就参考了 https://blog.csdn.net/qhs1573/article/details/100524255 里面对批处理截取字符的运用,但是还没人系统归纳过
遇到的问题
以前知道PowerShell在Windows Server的2008/2012/2016上,都要各写一套,在2012上写的,在2008和2016运行都有问题,今天发现CMD也有这样的问题,微软是真的很离谱。
现象就是运行上述代码只创建文件夹不创建文件。
于是经过各种坑,最终分拆了1.txt为k.txt和i.txt,分别存了两个盘的路径,并写了如下的代码。
@echo off
for /f "delims=" %%a in ('type "E:\aaaa\k.txt"') do (
if not exist "E:\bbbbb%%~pa" mkdir "E:\bbbbb%%~pa"
copy "\\192.168.101.100\ak1%%~pa%%~nxa" "E:\bbbbb%%~pa%%~nxa"
)
for /f "delims=" %%a in ('type "E:\aaaa\i.txt"') do (
if not exist "E:\ccccc%%~pa" mkdir "E:\ccccc%%~pa"
copy "\\192.168.101.105\qq_1\qqq_1%%~pa%%~nxa" "E:\ccccc%%~pa%%~nxa"
)
pause
说明一下意思,在服务器上K盘和I盘是两个盘,分别对应的是\\192.168.101.100\ak1和\\192.168.101.105\qq_1\qqq_1。
遇到哪些坑呢?
- 在Windows Server 2008上可以直接通过挂盘盘符访问文件,比如
K:/dcsgs/ppy/051zz/01zzfile/axcazppy2cgbgzz.file
,但是现在在2016上必须使用\192.168.101.100\ak1/dcsgs/ppy/051zz/01zzfile/axcazppy2cgbgzz.file
访问。 - 不要使用传参。由于需要拼接附件名,中间为了DEBUG,对参数使用了赋值并echo,赋值命令形如
set SOURCEPATH="\\192.168.101.100\ak1%%~pa%%~nxa"
这样,但是echo %SOURCEPATH%
会出现第一次赋值失败,第二次赋值成功的奇葩现象,一样的脚本不一样的结果,因此取消了中间传参过程。 %%~pa
是掐头去尾的中间路径,后面还需要拼接文件名。但是%%~na
显示的是无文件后缀的文件名,必须用%%~nxa
才能显示文件名加后缀名,不知道%%~pnxa
是不是可以直接满足%%~pa
和%%~na
拼接的需求,如果有哪位同学尝试了,请留言这样做是否可以。- copy不一定能新建文件夹,所以需要先创建文件夹后copy,所以才加了
if not exist "E:\ccccc%%~pa" mkdir "E:\ccccc%%~pa"
这个语句。
更新
补充:其实修改附件文件
K:/dcsgs/ppy/051zz/01zzfile/axcazppy2cgbgzz.file
# 把/改成\
K:\dcsgs\ppy\051zz\01zzfile\axcazppy2cgbgzz.file
就可以用
@echo off
for /f "delims=" %%a in ('type "1.txt"') do "C:\Windows\System32\xcopy.exe" "%%a" "F:\20211111\i\%%~pa" /s /y
pause
另外还有看到其他写法,比如借助excel直接枚举所有文件的,也是一个不错的方式