基于文件名的批量移动,不带分隔符,仅限字符串

时间:2016-10-07 18:52:22

标签: string windows batch-file cmd delimiter

好的,Windows 7 Enterprise x64此处带有Windows批处理文件问题。我是一个基本用户,对创建批处理文件知之甚少。我已经修改了我在线使用的现有脚本,就是它。

我有一个软件可以将它的输出转储到一个文件夹,文件名从项目标题,当前系统日期,当前系统时间和项目设置中连接起来。

每次保存项目时,它将以此格式导出两个文件:

PROJECTTITLE_2016_10_07__09_45_11__A_B_C.iges
PROJECTTITLE_2016_10_07__09_45_11__A_B_C.step

A,B和C表示软件中使用的特定于项目的开关。这些可能存在或可能不存在,因为文件名可以是_R_F或_R_F_Z等。 " PROJECTTITLE"从字面上看可以做任何事。这是我使用分隔符出现问题的地方。您可能拥有类似以下所有文件名(使用用户的实例):

11475shacklebody_2016_10_07__09_45_11__R_F.iges
11475shacklebody_2016_10_07__09_45_11__R_F.step
test_EFMflow_2016_10_07__09_45_11__R_Z.iges
test_EFMflow_2016_10_07__09_45_11__R_Z.step
untitled16_2016_10_07__09_45_11__R.iges
untitled16_2016_10_07__09_45_11__R.step
#14drop_wire-edm_2016_10_07__09_45_11__R_F_Z.iges
#14drop_wire-edm_2016_10_07__09_45_11__R_F_Z.step
prooftestwithoutupperlandsimproved-4_2016_10_07__09_45_11.iges
prooftestwithoutupperlandsimproved-4_2016_10_07__09_45_11.step

我想要做的是将IGES和STEP文件从C盘上的输出文件夹移动到网络驱动器上的新文件夹,其名称基于" PROJECTTITLE,"如果需要,创建该文件夹。我已经安排了一个基于-delim的批处理程序每​​晚运行的任务,但发现分隔符不足以供我使用。

虽然使用分隔符似乎很容易,但是在寻找第一个下划线时,我的名字中有下划线的项目会破坏文件夹的命名。由于分隔符只适用于单个字符,而不是字符串,我一直在寻找批量文件的例子,我可以适应我的使用,没有运气找到任何类似于我想做的不使用分隔符。

看起来很简单,搜索字符串" _2016,"在文件名中,并在" _2016"之前取出所有字符。并创建一个新目录,将包含这些字符的文件放在该文件夹中。我虽然没有分隔符,却迷失了如何做到这一点。

到目前为止,我使用分隔符查找下划线,创建文件夹并移动到映射驱动器上的这些文件夹:

for /f "delims=_" %%V in ('dir /b /a-d C:\Output\*_*.iges') do (
 mkdir "I:\ENG\PARTS\%%V" 2>nul
 move "C:\Output\%%V_*.iges" "I:\ENG\PARTS\%%V" >NUL 2>nul
 move "C:\Output\%%V_*.step" "I:\ENG\PARTS\%%V" >NUL 2>nul
)

这是一个非常简单的批处理文件,但它与标题包含下划线的表面不同。

一些事情:

搜索_2016意味着批处理文件需要每年维护。我们可以搜索系统%YEAR%,还是以某种方式搜索"_####_##_##_",使用正则表达式来远离搜索系统日期或特定年份?

修改 虽然不太理想,因为交换机很有用,但我发现软件中的一种方法是不在文件名末尾导出项目特定的交换机。所以现在出口将是:

PROJECTTITLE_2016_10_07__09_45_11.iges
PROJECTTITLE_2016_10_07__09_45_11.step

我知道我可以从右边修剪,21个字符,使用该名称创建文件夹并在目录中搜索包含该修剪过的字符串的所有文件。

尽管开关完好无损,但仍然可以找出如何搜索特定字符串。我愿意学习,所以请向我提出你的代码的所有解释。

Double(Late)EDIT: 首先,谢谢大家的回答,我非常感谢你的帮助。

文件名中的双下划线非常罕见,但确实发生了,可能是由于拼写错误。对于我计划随此移动的文件量而言,这变得更加困难。该软件可运行在大约100台用户计算机上,其中20个左右是重度用户,每天最多可节省1000个文件。当用户运行模拟时,软件将自动以增量方式保存。我试图给他们一种方法来通过网络协作和查看彼此的模拟结果(我们积极鼓励他们使用),并且它认为该软件是硬编码输出到C驱动器的(对于"表现"正如供应商告诉我的那样)。我正在考虑安排文件在其OU中的每台PC上每15分钟移动一次,而不是每晚,以便近乎实时地查看他们正在处理的内容。

我探索的另一个选项是象征性地将每台计算机上的输出文件夹链接到软件的文件夹网络驱动器,但发现这确实无法解决用户组织的问题#" 34;问题,把项目运行放在同一个文件夹中。这也有一个问题,就是不允许他们在没有VPN的情况下将项目保存在办公室之外,有些用户会这样做,然后当他们回到办公室时将文件移出。

感谢您的协助。

4 个答案:

答案 0 :(得分:1)

即使文件名包含{em> space 或cmd 百分号%

@ECHO OFF
SETLOCAL EnableExtensions DisableDelayedExpansion

set "_fouts=C:\Output"           your setting
set "_fouts=D:\test\39924063"    my setting 

for /F %%G in ('wmic OS get localdatetime ^|find "."') do set "_fyear=%%G"

pushd "%_fouts%"
  set "_fyear=%_fyear:~0,4%"
  call :doDir
  set /A _fyear -= 1
  call :doDir
popd

ENDLOCAL
goto :eof

:doDir
rem debugging output echo(%_fyear%
for /f "delims=" %%V in ('
  dir /b /a-d "*_%_fyear%_*.iges" "*_%_fyear%_*.step" 2^>NUL') do (
    set "_fname=%%~nV"           filename without extesion
    set "_fexte=%%~xV"           extesion only
    call :doAll
)
goto :eof

:doAll
    call set "_ftail=%%_fname:*_%_fyear%_=%%"
    call set "_fproj=%%_fname:_%_fyear%_%_ftail%=%%"
    rem debugging output echo("%_fproj%" "%_fname%" "%_fexte%"
    ECHO mkdir "I:\ENG\PARTS\%_fproj%" 2>nul
    ECHO move "%_fname%%_fexte%" "I:\ENG\PARTS\%_fproj%\"
goto :eof

输出(请注意,操作mkdirmove命令仅用于分别使用ECHO mkdirECHO move显示以进行调试:< / p>

==> dir /B /S "D:\test\39924063" /S
D:\test\39924063\#14drop_wire-edm_2016_10_07__09_45_11__R_F_Z.iges
D:\test\39924063\#14drop_wire-edm_2016_10_07__09_45_11__R_F_Z.step
D:\test\39924063\%PROJECT TITLE_2016_10_07__09_45_11__A_B_C.iges
D:\test\39924063\%PROJECT TITLE_2016_10_07__09_45_11__A_B_C.step

==> D:\bat\SO\39924063.bat
mkdir "I:\ENG\PARTS\#14drop_wire-edm"
move "#14drop_wire-edm_2016_10_07__09_45_11__R_F_Z.iges" "I:\ENG\PARTS\#14drop_wire-edm\"
mkdir "I:\ENG\PARTS\%PROJECT TITLE"
move "%PROJECT TITLE_2016_10_07__09_45_11__A_B_C.iges" "I:\ENG\PARTS\%PROJECT TITLE\"
mkdir "I:\ENG\PARTS\#14drop_wire-edm"
move "#14drop_wire-edm_2016_10_07__09_45_11__R_F_Z.step" "I:\ENG\PARTS\#14drop_wire-edm\"
mkdir "I:\ENG\PARTS\%PROJECT TITLE"
move "%PROJECT TITLE_2016_10_07__09_45_11__A_B_C.step" "I:\ENG\PARTS\%PROJECT TITLE\"

==>

资源(必读,不完整):

答案 1 :(得分:1)

@ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
REM (
FOR /f "delims=" %%a IN (
 'dir /b /a-d "%sourcedir%\*__*" '
 ) DO (
IF /i "%%~xa"==".iges" CALL :process "%%a"
IF /i "%%~xa"==".step" CALL :process "%%a"
)
REM )>"%outfile%"

GOTO :EOF

:: Process filename "%1"
:process
SET "fullname=%~1"
SET "junk=%fullname:*__=%"
CALL SET "project=%%fullname:%junk%=%%"
SET "project=%project:~0,-13%
ECHO(MD "%destdir%\%project%"
ECHO(MOVE "%sourcedir%\%~1" "%destdir%\%project%\"
GOTO :eof

您需要更改sourcedirdestdir的设置以适合您的具体情况。

所需的MD命令仅用于ECHO用于测试目的。 在您确认命令正确无法后,将ECHO(MD更改为MD以实际创建目录。附加2>nul以禁止错误消息(例如,当目录已存在时)

为了测试目的,所需的MOVE命令仅为ECHO在您确认命令正确后,将ECHO(MOVE更改为MOVE以实际移动文件。附加>nul以取消报告消息(例如1 file moved

此方法只执行目录列表,而不包含源目录中包含双下划线的每个文件的目录名(/a-d)。每个文件名匹配都分配给%%a,如果扩展部分(%%~xa)是其中一个目标,则处理文件名。

处理包括删除双下划线之前的所有字符,然后从全名中删除该垃圾部分,给出项目+日期。删除最后13个字符,您就拥有了项目名称。

任何包含某些符号的文件名都会出现问题,例如 = ,但下划线应该没问题。

答案 2 :(得分:1)

假设文件名的PROJECTTITLE部分不包含两个连续的下划线,您可以使用以下脚本,它将第一次出现的__和之后的所有内容分开(因此时间部分和可选开关是已移除),使用标准for循环而不是for /F;然后它使用子字符串扩展分割另外11个字符(因此剩余的日期部分):

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "_SOURCE=."
set "_TARGET=."

for /F delims^=^ eol^= %%F in ('
    pushd "%_SOURCE%" ^&^& ^(
    dir /B /A:-D ^
        "*_????_??_??__??_??_??*.iges" ^
        "*_????_??_??__??_??_??*.step" ^
    ^& popd^)
') do (
    call :PROCESS "%%F"
)

endlocal
exit /B


:PROCESS  val_file
setlocal DisableDelayedExpansion
set "FILE=%~1"
setlocal EnableDelayedExpansion
for %%I in ("!FILE:__=";"!") do (
    endlocal
    set "ITEM=%%~I"
    setlocal EnableDelayedExpansion
    goto :NEXT
)
:NEXT
if defined ITEM (
    set "ITEM=!ITEM:~,-11!"
    md "%_TARGET%\!ITEM!" 2> nul
    if not exist "%_TARGET%\!ITEM!\!FILE!" (
        move /Y "%_SOURCE%\!FILE!" "%_TARGET%\!ITEM!\" > nul
    )
)
endlocal
endlocal
exit /B

最后,我想出了一个脚本,它能够处理PROJECTTITLE部分自己包含__的文件。它会删除最后一次出现的__以及之后的所有内容(因此删除可选开关,如果有的话,或者删除时间部分),使用标准for循环而不是{{1} };那么它会分割掉另外21个字符(因此剩下的日期和时间部分),或者,如果没有可选的开关,只需要另外11个字符(因此剩下的日期部分),使用子字符串扩展:

for /F

答案 3 :(得分:1)

此版本假设_YYYY_中没有PROJECTTITLE的实例。

@Echo Off
SetLocal EnableExtensions DisableDelayedExpansion

(Set OutDir=I:\ENG\PARTS)
(Set SrcDir=C:\Output)

If Not Exist "%SrcDir%\" Exit/B 1
If Not Exist "%OutDir%\" Exit/B 1
For /F "EOL=Y" %%A In ('WMIC Path Win32_LocalTime Get Year') Do (
    For /F "Delims=" %%B In ("%%A") Do Set "ThisYr=%%B")
For /F "Delims=" %%A In ('Where "%SrcDir%:*_%ThisYr%_*.iges"') Do (
    If Exist "%%~dpnA.step" Call :Sub %%~nA)
Exit/B

:Sub
Set "BigTit=%~1"
For /F "Delims=" %%A In ('CMD /Q /C "Call Echo %%BigTit:_%ThisYr%_=&:%%"') Do (
    If Not Exist "%OutDir%\%%A\" MD "%OutDir%\%%A"
    Move "%SrcDir%\%~1*.*" "%OutDir%\%%A">Nul)

编辑 ,如果没有使用上述代码的潜在有用项目开关,则无需导出。