BATCH:如何根据文件名

时间:2017-12-07 17:11:51

标签: windows batch-file cmd

我正在努力为我工作的公司存档很多文件。我对Batch脚本有点熟悉,但我还不太了解完全了解我的目标。

我正在尝试将基于文件名开头的一些文件复制到NAS上的文件夹中。这些文件是7z文件,它们的结构如下:

  • 5476 BMW Handle-A.7z
  • 5487 Chevy-Imp.7z
  • 5986 Honda Lid-Upper.7z

文件结构的工作原理如下:开头的四个数字是我们公司的工号。在我们的NAS上,我们有一个存档目录,其中包含文件夹:

  • _5000-5999
  • _6000-6999

这些文件夹中包含每个包含250个存档文件的文件夹。它们的格式如下:

  • _5000-5249
  • _5250-5499
  • _5500-5749
  • _5750-5999

我希望创建一个Batch文件,我可以将这些7z文件拖到它上面,它将读取文件名的前四个数字,并将其复制到我们NAS上的正确文件夹中。

例如文件:

  • 5476 BMW Handle-A.7z
  • 5487 Chevy-Imp.7z

将复制到

\ nas01 \ archive \ _5000-5999 \ _5250-5499

等。

我正在弄乱的主要代码是:

@echo off 
for /f "delims=" %%i in ('dir /b /a-d *.7z') do (
set "filename1=%%~i"
setlocal enabledelayedexpansion
set "folder1=!filename1:~0,4!"
mkdir "!folder1!" 2>nul
copy "!filename1!" "!folder1!" >nul
)

对我来说不起作用的是这一行:

set "folder1=!filename1:~0,4!"

如何创建某种变量来检查文件名,必要时创建文件夹并将其复制到正确的文件夹?我将不胜感激任何帮助!

-Dustin

2 个答案:

答案 0 :(得分:1)

感谢评论者的一些帮助,我能够弄清楚。我遇到了如何构建脚本的问题,但我明白了!

Option Explicit

Sub MixColumns()

    Dim ws As Worksheet
    Dim rngIn As Range
    Dim rngOut As Range
    Dim lng As Long
    Dim rngArea As Range
    Dim rngCell As Range

    Set ws = ThisWorkbook.Worksheets("Sheet1")

    ' example 1
    Set rngIn = ws.Range("B1:C1,E1:F1,G1") '<-- 5 cells, non-contiguous, forward order
    Set rngOut = ws.Range("B2:F2") '<-- 5 contiguous cells

    rngIn.Copy rngOut '<-- works


    ' example 2 - OP problem
    Set rngIn = ws.Range("E1:F1,G1,B1:C1") '<-- 5 cells, non-contiguous, odd order
    Set rngOut = ws.Range("B3:F3") '<-- 5 contiguous cells

    rngIn.Copy rngOut '<-- should be e,f,g,b,c but gets b,c,e,f,g


    ' example 3 - solution for OP problem
    Set rngIn = ws.Range("E1:F1,G1,B1:C1") '<-- 5 cells, non-contiguous, odd order
    Set rngOut = ws.Range("B4:F4") '<-- 5 contiguous cells

    lng = 1 '<-- rngOut cell counter
    ' iterate areas
    For Each rngArea In rngIn.Areas
        ' iterate cells in area
        For Each rngCell In rngArea.Cells
            rngOut.Cells(1, lng).Value = rngCell.Value '<-- copy single value
            lng = lng + 1 '<-- increment rngOut counter
        Next rngCell
    Next rngArea '<-- results in e,f,g,b,c


End Sub

我今天学到了更多关于Batch的知识,所以这是花了一天时间!

有没有办法让你可以点击并将文件拖到这个批处理脚本而不是抓取文件夹中的所有7z文件?

答案 1 :(得分:1)

以下是此任务的完整批处理代码,主要使用算术表达式和字符串连接来确定源文件夹中每个* .7z文件的目标文件夹路径,或者对于通过参数将名称传递给的每个文件。批处理文件。

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem Source path is the directory of the batch file ending with a backslash.
set "SourcePath=%~dp0"
rem Target path is a UNC path also ending with a backslash.
set "TargetPath=\\nas01\archive\"

rem Run subroutine ProcessFile for each *.7z file in source folder
rem if not at least 1 file was specified on command line to process.
rem Otherwise process the files of which names are passed as arguments
rem to this batch file on starting it. 
if "%~1" == "" (
    for %%I in ("%SourcePath%*.7z") do call :ProcessFile "%%I"
) else (
    for %%I in (%*) do call :ProcessFile "%%~I"
)

rem Restore previous environment and exit this batch file.
endlocal
goto :EOF


rem The subroutine ProcessFile determines the target folders based on
rem first part of the file name separated with one or more spaces from
rem rest of the file name which should be a positive integer number.

rem File names not starting with a valid number are copied (or moved)
rem to the folder _0000-0249\_0000-0249 in specified target folder.

rem For file numbers less than 1000 an extra code is added to copy (or move)
rem those files into folders also having at least 4 digit numbers in name.

:ProcessFile
for /F %%J in ("%~n1") do set "FileNumber=%%J"
set /A FolderNumber1=(FileNumber / 1000) * 1000
set /A FolderNumber2=FolderNumber1 + 999

set /A FolderNumber3=FileNumber - FolderNumber1
if %FolderNumber3% LSS 250 (
    set "FolderNumber3=%FolderNumber1%"
    set /A FolderNumber4=FolderNumber1 + 249
    goto BuildFolderPath
)
if %FolderNumber3% LSS 500 (
    set /A FolderNumber3=FolderNumber1 + 250
    set /A FolderNumber4=FolderNumber1 + 499
    goto BuildFolderPath
)
if %FolderNumber3% LSS 750 (
    set /A FolderNumber3=FolderNumber1 + 500
    set /A FolderNumber4=FolderNumber1 + 749
    goto BuildFolderPath
)
set /A FolderNumber3=FolderNumber1 + 750
set "FolderNumber4=%FolderNumber2%"

:BuildFolderPath
if %FolderNumber1% == 0 (
    set "FolderNumber1=0000"
    set "FolderNumber2=0%FolderNumber2%"
    set "FolderNumber4=0%FolderNumber4%"
    if %FolderNumber3% == 0 (
        set "FolderNumber3=0000"
    ) else (
        set "FolderNumber3=0%FolderNumber3%"
    )
)
set "TargetFolder=%TargetPath%_%FolderNumber1%-%FolderNumber2%\_%FolderNumber3%-%FolderNumber4%"

mkdir "%TargetFolder%" 2>nul
copy /Y "%~1" "%TargetFolder%\" >nul
rem move /Y "%~1" "%TargetFolder%\" >nul
goto :EOF

使用子程序而不是在 FOR 循环中执行所有操作,因为这使得任务更容易编码,因为 GOTO 可以在子例程中使用。使用子程序时,没有必要使用延迟的环境变量扩展,这在* .7z文件包含感叹号的情况下很有用。

此解决方案的主要优点:它适用于文件名中范围为0到2147482999的数字。

要了解使用的命令及其工作原理,请打开命令提示符窗口,执行以下命令,并完全阅读为每个命令显示的所有帮助页面。

  • call /?
  • copy /?
  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • if /?
  • mkdir /?
  • move /?
  • rem /?
  • setlocal /?

另请阅读Microsoft有关Using Command Redirection Operators解释>nul2>nul的文章,该文章用于将成功和错误消息重定向到设备 NUL 以禁止它们。