使用Windows命令行增加文件夹名称编号

时间:2017-06-17 10:50:04

标签: batch-file cmd powershell-v2.0

我每周都会创建一个新文件夹,为了使它们按顺序排列,我使用01 - day-month02 - day-month等编号命名它们。我已经创建了windows cmd脚本来命名根据日期的文件夹,但现在我想编写脚本的一部分,将文件夹的编号放在日期之前(保持数字用虚线表示)。

我已经在stackexchange上看到了一个示例,但无法完全理解代码。

这是我到目前为止所得到的:

@echo off
setlocal enableDelayedExpansion
set "baseName= - "
set "n=0"
for /f "delims=" %%F in (
  '2^>nul dir /b /ad "%baseName%*."^|findstr /xri "[0-9]*%baseName%*"'
) do (
  set "name=%%F"
  set "name=!name:*%baseName%=!"
  if !name! gtr !n! set "n=!name!"
)
set /a n+=1
md "%n%%baseName%"

欢迎使用PowerShell 2.0。

2 个答案:

答案 0 :(得分:2)

@echo off
setlocal enableDelayedExpansion
set "baseName= - "
set "n=0"
for /f "delims= " %%F in (
  '2^>nul dir /b /ad "*%baseName%*."^|findstr /xri /c:"[0-9][0-9]%baseName%.*"'
) do (
  if %%F gtr !n! set "n=%%F"
)
IF %n%==0 (SET /a n=100) ELSE (SET "n=1%n%")
set /a n+=1
echo md "%n:~-2%%baseName%"

GOTO :EOF

我会解释一些变化。

首先,dir命令以/b目录名的/ad(基本)形式输出目录列表。正如@compo所说,您需要*%basename%*,因为您的目录名的格式为nn - something,而不是%basename%2^>nul指示来自dir的任何错误报告(例如no files found)都会被取消。

此命令的输出然后管道findstr,选择行/xri e x 的行,case- I 与提供的 R egular表达式无差别地匹配。

原始regex," [0-9] %baseName%"是不够的。它试图说"任意数量的前导数字(包括根本没有前导数字)"然后是basename后跟*的字符串,后面跟basename"

中的任意数字#{1}}

此外,由于basename包含 Space ,因此findstr将每个以空格分隔的子字符串视为要查找的单独字符串,因此会尝试查找并完全匹配" any位数"或" - "或者" *",所以它没有产生任何结果就不足为奇了。

替换regex首先是/c:,这意味着"空格是普通字符"然后正则表达式本身指定两个前导数字,basename字符串和.* - 任何其他字符的任意数字(因为您的待检查目录名将被重命名为02 - day-month

通过将delims设置为空格,分配给%%F的(隐式默认单个标记)将是列表中目录名中的任何字符(在findstr过滤后)最多但不包括第一个空间

所以,现在要做的就是找到%%F中的最高数值。这是通过将%%Fn的值进行比较(将来,请使用有意义的名称)并将n设置为%%F的值,如果 < / em>更大。

由于!n!特征,需要delayed expansion语法(有很多很多关于此的SO文章 - 使用顶部栏中的search查找一些内容)。本质上,在代码块(带括号的一系列命令)中,任何%var%都会被遇到块时的变量值替换,!var!(调用delayedexpansion)是运行时值(通过块操作改变的值)

一旦完成循环,我们就会遇到以下两种情况之一:要么没有匹配(因此n将具有值0),或者匹配所以n会有匹配值nn,将为2位数)

set /a会增加n中的值,这一切都很好 - EXCEPT 如果n恰好是08或{ {1}},操作将失败,因为09看到一个数字字符串从cmd开始为八进制08无效八进制字符。

此问题的标准解决方法是在两位数值之前将9字符串。显然,如果1n,那么将0添加到1 - 并且您需要前导零,因此在这种情况下,请将1设置为n。 (我使用了强制算术100

在增加数字后,set现在需要md的最后2个字符,因此n的含义是%n:~-2%。我只是echo修改了提议的新名称,以防出现问题。在您进行测试后,只需删除echo关键字即可激活md

最好是剪切和粘贴解决方案,因为批处理可以表现出奇怪的语法敏感性。它也避免了拼图。

答案 1 :(得分:1)

这是我的解决方案,使用了一种快速的方法,除了 WMIC 命令的执行外,当前日期和月份应该从当地日期/时间确定时无法避免。区域和语言无关的方式。重新格式化环境变量 DATE 的字符串会更快,但此日期字符串的格式取决于为使用的用户帐户定义的Windows区域设置。

包含大量注释行的批处理代码(以命令 REM 开头的行):

@echo off
goto GetFolderList

rem Run DIR to get a list of only folder names because of /AD and /B
rem matching the wildcard pattern ?? - ??-?? ordered reverse by name
rem because of /O-N with suppressing the error message DIR outputs if
rem no such folder can be found in current directory by redirecting
rem the error message to device NUL.

rem From folder name just the first two characters are assigned to loop
rem variable I as the default delimiters space/tab are used on splitting
rem up the folder name into tokens. Only the first token is processed by
rem outer FOR with the default options, i.e. the number to increment.

rem The inner FOR executes the SET command only if the first space/tab
rem delimited string of current folder name from DIR output contains any
rem non digit character. So if environment variable Number is defined
rem after inner FOR loop execution, the folder name is not valid as it
rem does not start with a number with 2 digits.

rem On current folder name not starting with a number, the outer FOR loop
rem is processed further with next folder name. Otherwise the number of
rem the current folder name being automatically the highest number because
rem of using leading zeros and reverse output by name is assigned to the
rem environment variable Number and outer FOR loop is exited with a jump
rem to label TrimNumber.

rem The numbering for first folder starts with 01 in case of no (valid)
rem folder matching wildcard pattern ?? - ??-?? is found in current folder.

:GetFolderList
set "Number="
for /F %%I in ('dir /AD /B /O-N "?? - ??-??" 2^>nul') do (
    for /F "delims=0123456789" %%J in ("%%I") do set "Number=none"
    if defined Number (
        set "Number="
    ) else (
        set Number=%%I
        goto TrimNumber
    )
)
set "Number=01"
goto CreateFolder


rem On incrementing a number with leading zeros using an arithmetic expression
rem it can happen easily that the number is interpreted octal, especially if
rem the number would have 3 digits which is not the case here. So it is better
rem to remove the leading zero(s) before incrementing the number by 1.

rem Of course with number from folder name being 00 it happens on removing
rem in a loop the first character from string when being 0 that the number
rem string is suddenly not defined anymore which must result also in an
rem exit of this loop trimming leading zeros.

:TrimNumber
if not "%Number:~0,1%" == "0" goto IncrementNumber
set "Number=%Number:~1%"
if defined Number goto TrimNumber
set "Number=01"
goto CreateFolder


rem After leading zeros are removed it is safe to increment the number by 1.
rem Then it is necessary to make sure that the number has always two digits
rem even on being 1 to 9. This can be achieved by inserting a leading 0 on
rem number string and then get just the last 2 characters from number string.

:IncrementNumber
set /A Number+=1
set "Number=0%Number%"
set "Number=%Number:~-2%"
goto CreateFolder


rem The WMIC command below with used options outputs among blank
rem lines in UTF-16 Little Endian encoding also a line with

rem LocalDateTime=20170617192138.218000+120

rem Of interest from this line is the string after the equal sign as it
rem contains year, month, day, hour, minute, second, microsecond and UTC
rem offset of configured time zone in fixed and region independent format.

rem From this date/time string just the month and day is needed for the
rem folder name in format DD-MM with incremented number being prepended.

:CreateFolder
for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "LocalDateTime=%%I"
set "FolderName=%Number% - %LocalDateTime:~6,2%-%LocalDateTime:~4,2%"
md "%FolderName%"

编辑:如Magoo所解释的那样,通过在1之前添加文件夹名称中的数字字符串来避免对前导0的数字进行八进制解释的方法很棒并且使得代码更容易,更快一点:

@echo off
goto GetFolderList

rem Run DIR to get a list of only folder names because of /AD and /B
rem matching the wildcard pattern ?? - ??-?? ordered reverse by name
rem because of /O-N with suppressing the error message DIR outputs if
rem no such folder can be found in current directory by redirecting
rem the error message to device NUL.

rem From folder name just the first two characters are assigned to loop
rem variable I as the default delimiters space/tab are used on splitting
rem up the folder name into tokens. Only the first token is processed by
rem outer FOR with the default options, i.e. the number to increment.

rem The inner FOR executes the SET command only if the first space/tab
rem delimited string of current folder name from DIR output contains any
rem non digit character. So if environment variable Number is defined
rem after inner FOR loop execution, the folder name is not valid as it
rem does not start with a number with 2 digits.

rem On current folder name not starting with a number, the outer FOR loop
rem is processed further with next folder name. Otherwise the number of
rem the current folder name being automatically the highest number because
rem of using leading zeros and reverse output by name is assigned to the
rem environment variable Number and outer FOR loop is exited with a jump
rem to label IncrementNumber.

rem The numbering for first folder starts with 01 in case of no (valid)
rem folder matching wildcard pattern ?? - ??-?? is found in current folder.

:GetFolderList
set "Number="
for /F %%I in ('dir /AD /B /O-N "?? - ??-??" 2^>nul') do (
    for /F "delims=0123456789" %%J in ("%%I") do set "Number=none"
    if defined Number (
        set "Number="
    ) else (
        set Number=%%I
        goto IncrementNumber
    )
)
set "Number=01"
goto CreateFolder


rem On incrementing a number with leading zeros using an arithmetic expression
rem it can happen easily that the number is interpreted octal, especially if
rem the number would have 3 digits which is not the case here. That can be
rem avoided here by changing the strings "00" to "99" to "100" to "199".

rem Next it is safe to increment the number by 1. Then it is necessary to get
rem from number in range 101 to 200 the last 2 characters from number string.

:IncrementNumber
set "Number=1%Number%"
set /A Number+=1
set "Number=%Number:~-2%"
goto CreateFolder


rem The WMIC command below with used options outputs among blank
rem lines in UTF-16 Little Endian encoding also a line with

rem LocalDateTime=20170617192138.218000+120

rem Of interest from this line is the string after the equal sign as it
rem contains year, month, day, hour, minute, second, microsecond and UTC
rem offset of configured time zone in fixed and region independent format.

rem From this date/time string just the month and day is needed for the
rem folder name in format DD-MM with incremented number being prepended.

:CreateFolder
for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "LocalDateTime=%%I"
set "FolderName=%Number% - %LocalDateTime:~6,2%-%LocalDateTime:~4,2%"
md "%FolderName%"

再补充一点:

这样的命令行
set "FolderName=%LocalDateTime:~0,4%-%LocalDateTime:~4,2%-%LocalDateTime:~6,2%
使用 WMIC 命令的 FOR 命令行后,

将以格式YYYY-MM-DD定义文件夹名称,这在文件夹和文件名中最常用,因为这样做国际日期格式按名称排序的文件和文件夹也会自动按日期排序。

因此,当不需要在同一天创建多个文件夹(文件夹名称中确实需要递增的数字)时,在文件夹名称中使用国际日期格式会更好,批处理代码可以简化为: / p>

@echo off
for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "LocalDateTime=%%I"
md "%LocalDateTime:~0,4%-%LocalDateTime:~4,2%-%LocalDateTime:~6,2%

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

  • dir /?
  • echo /?
  • for /?
  • goto /?
  • if /?
  • rem /?
  • set /?
  • wmic /?
  • wmic os /?
  • wmic os get /?
  • wmic os get localdatetime /?

另请阅读有关Using Command Redirection Operators的Microsoft文章,了解2>nul的说明。重定向操作符>必须使用插入符号^进行转义,以便在解析整个 FOR 命令行时由Windows命令解释程序解释为文字字符,稍后执行 WMIC 命令行由FOR作为重定向运算符。