如何使用批处理文件将位于当前目录中的文本文件名获取到变量
How to get a text file name in located in current directory to a variable with a batch file
我有一个 .txt
文件,根据命名方案 ASyymm-sn
,yy
是当前年份,其名称用作格式 AS2204-1
的参考没有世纪,mm
是当前月份,sn
是当前月份的序列号。我尝试获取当前文件名并在年月不变的情况下将序列号递增1,将新文件名复制到剪贴板,然后重命名文本文件。
到目前为止,这是我的代码:
@echo off
set yy=%date:~12,2%
set mm=%date:~4,2%
set /a sn=0
for %%a in ('dir *.txt') do (set filename=%%a)
set Fmm=%filename:~5,2%
if %Fmm%==%mm% (set /a sn=sn+1) else (set /a sn=1)
echo AS%yy%%mm%^-%sn% |clip
ren "%filename%.txt" "AS%yy%%mm%^-%sn%.txt"
我无法获取分配给变量 filename
的文件名。
我的代码有什么问题,什么是正确的 FOR 循环?
可以使用以下批处理文件来完成此任务:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
for /F "tokens=1,2 delims=/" %%G in ('%SystemRoot%\System32\robocopy.exe "%SystemDrive%\|" . /NJH') do set "YearMonth=%%G%%H" & goto SearchFile
:SearchFile
set "SerialNumber=0"
set "FileNameScheme=AS%YearMonth:~2%-"
for %%G in ("%FileNameScheme%*.txt") do for /F "tokens=2 delims=-" %%H in ("%%~nG") do if %%H GTR !SerialNumber! (set "SerialNumber=%%H" & set "FileName=%%G")
set /A SerialNumber+=1
echo %FileNameScheme%%SerialNumber%| %SystemRoot%\System32\clip.exe
if defined FileName (
ren "%FileName%" "%FileNameScheme%%SerialNumber%.txt"
) else (
rem del /Q "AS????-*.txt" >nul 2>nul
echo %FileNameScheme%%SerialNumber%>"%FileNameScheme%%SerialNumber%.txt"
)
endlocal
前两行完全定义了所需的执行环境是:
- 命令回显模式关闭
- 命令扩展已启用
- 启用延迟变量扩展
请阅读我在 Time is set incorrectly after midnight 上的回答中的 使用 ROBOCOPY 获取当前 date/time 一章,以了解 FOR 的解释 命令行使用 ROBOCOPY 获取当前年份和月份独立于为使用的帐户配置哪个国家(地区)决定动态变量的日期格式 DATE
.
首先定义环境变量SerialNumber
,默认值为0
。
环境变量 FileNameScheme
以 AS
开始定义,没有世纪的当前年份始终为两位数,当前月份始终为两位数和 -
结果今天在字符串 AS2204-
.
中
命令FOR用于在当前目录(可以是任意目录)搜索一个或多个non-hidden匹配通配符模式 AS2204-*.txt
.
的文件
目前尚不清楚我的文件如何位于与通配符模式匹配的当前目录中 AS????-*.txt
。因此,编写的代码也适用于当前目录中与此通配符模式匹配的多个文件。
对于每个与当前年份和月份匹配的通配符模式的文件名,已经包含一个 FOR 循环用于获取连字符和文件扩展名之间的字符串,希望是始终是 0
到 2147483647
范围内的数字,不带前导零。
这个数字字符串与环境变量SerialNumber
的当前值进行比较。由于此数字比较,必须启用延迟变量扩展。如果当前文件的编号大于当前序列号,则继续使用较大的数字作为序列号,并将当前文件的名称赋值给环境变量FileName
.
请注意,GTR
不适用于文件中有前导零的数字,因为在这种情况下,数字将被解释为八进制而不是十进制数,这意味着 08
和 09
将被解释为无效的八进制数,在这种情况下使用值 0
进行数字比较。
默认值0
或匹配AS2204-*.txt
的最大文件数接下来使用算术表达式递增1。
出于任何目的将带有递增序列号的文件名不带文件扩展名复制到剪贴板。
如果真的找到了名称中包含当前年份和月份的文件,现在将此文件重命名为包含加一的序列号。否则,将使用新文件名创建一个新文件,并包含不带文件扩展名的文件名作为数据,例如 AS2204-1
.
有一行用命令 REM 注释掉,这将删除所有匹配通配符模式 AS????-*.txt
的文件,除了被命令 忽略的隐藏文件默认情况下 DEL 和 read-only 文件未被命令删除 DEL 默认情况下以及当前正在被应用程序打开的匹配文件。目前尚不清楚如何处理前一个月匹配此模式的其他文件。
如果当前目录中没有或始终只有一个文件匹配通配符模式 AS????-*.txt
,则批处理文件代码可以优化为以下命令行:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "tokens=1,2 delims=/" %%G in ('%SystemRoot%\System32\robocopy.exe "%SystemDrive%\|" . /NJH') do set "YearMonth=%%G%%H" & goto SearchFile
:SearchFile
set "SerialNumber=0"
set "FileNameScheme=AS%YearMonth:~2%-"
for %%G in ("%FileNameScheme%*.txt") do for /F "tokens=2 delims=-" %%H in ("%%~nG") do set "SerialNumber=%%H"
set /A SerialNumber+=1
echo %FileNameScheme%%SerialNumber%| %SystemRoot%\System32\clip.exe
if exist "AS????-*.txt" (
ren "AS????-*.txt" "%FileNameScheme%%SerialNumber%.txt"
) else (
echo %FileNameScheme%%SerialNumber%>"%FileNameScheme%%SerialNumber%.txt"
)
endlocal
不再需要延迟变量扩展,这使得批处理文件的处理速度稍微快了一点。带有一个或多个前导零的序列号仍然是一个问题,因为命令 SET 在计算算术表达式时将数字字符串也转换为整数,并将数字解释为八进制数数字字符串开头的字符 0
。
为了了解使用的命令及其工作原理,请打开 command prompt window,在其中执行以下命令,并仔细阅读为每个命令显示的所有帮助页面。
del /?
echo /?
endlocal /?
for /?
goto /?
if /?
rem /?
robocopy /?
set /?
setlocal /?
另请参阅:
- 关于 Using command redirection operators
的 Microsoft 文档
- Single line with multiple commands using Windows batch file 无条件命令运算符的解释
&
.
@echo off
setlocal
pushd "?:\whichever\directory\contains your\target files"
set "yy=%date:~12,2%"
set "mm=%date:~4,2%"
set "filename="
for /f %%a in ('dir /b /a-d /od AS%yy%%mm%-*.txt 2^>nul') do (set "filename=%%~na")
rem use this line if you use suppressed leading zero
if defined filename (set /a "sn=%filename:*-=%+1") else (set /a sn=1)
rem use this line if you use 2-digit
if defined filename (set /a "sn=1%filename:~-2%+1") else (set /a sn=101)
IF %sn% gtr 100 SET "sn=%sn:~-2%"
echo AS%yy%%mm%-%sn%
ren "whatever.txt" "AS%yy%%mm%-%sn%.txt"
POPD
goto :eof
setlocal
确保在批处理终止时删除环境更改(新变量)。
pushd
切换到指定目录。我不知道你的目录是什么。
语法 SET "var=value"
(其中值可能为空;在这种情况下 var
变为 undefined)用于确保任何杂散尾随空格不包括在分配的值中。
for /f
将dir
“报告”的每一行依次分配给%%a
。因此,filename
将仅设置为找到的文件名的名称部分 (%%~na
)。 dir /b
以基本形式(仅文件名)生成要处理的文件列表。 /a-d
排除目录名,/od
按日期顺序生成列表。文件掩码 AS%yy%%mm%-*.txt
要求匹配 AS
+thecurrentyearnumber+thecurrentmonthnumber+-
的所有 .txt
个文件,因此没有必要检查 year/month 部分。如果找不到与掩码匹配的文件名,2^>nul
会抑制错误消息。
如果找到文件名,filename
将被定义。这就是为什么它在 for
循环之前设置为 nothing(un 定义它)。
文件名必须按日期顺序生成,因为 ASyymm-10
将在默认 name-order 列表中排序 之前 ASyymm-2
。
嗯,我不知道您使用的是 1 位还是 2 位序列号 - 处理方式不同。
如果你使用第一个 if defined...
然后 sn
被设置为比 filename
多 1 的部分(当 -
之前的所有字符都存在时 filename
的那部分删除)或 1
如果没有找到先前的文件。
如果你使用第二个if defined...
那么sn
设置为比(1
+filename
的最后2个字符)多1或101
如果没有找到先前的文件,那么 ASyymm-07
将产生 sn=108
。这是必要的,因为在计算中批处理将 0
开头的数字字符串解释为 OCTAL。
如果结果>100,则使用sn
的最后2个字符。
我刚刚 echo
将所需的字符串输入到屏幕上。如果需要,回显到剪贴板。
嗯 - 重命名。不清楚要重命名为计算名称的文件是什么,所以我使用了whatever
。可能是一个名为 ASyymm.txt
的文件 - 如果是这样,请将 whatever
替换为 AS%yy%%mm%
.
popd returns到原目录。
对于大多数命令,可以通过执行 commandname /?
来获取文档,但有时可能会有点含糊。只需在 SO 中搜索示例即可。
首先感谢大家的回答!
我是这样做的 - 它工作正常,直到重命名部分不起作用 - 知道为什么吗?
set "yy=%date:~12,2%"
set "mm=%date:~4,2%"
set "filename=\root\*.txt"
for %%A in (%filename%) do (set x=%%~nA)
set Fmm=%x:~4,2%
set sn=%x:7.1%
if %Fmm%==%mm% (set /a sn=sn+1) else (set /a sn=1)
echo AS%yy%%mm%^-%sn% |clip
set newfilename=AS%yy%%mm%-%sn%.txt
set oldfilename=%x%.txt
ren %oldfilename% %newfilename%
我有一个 .txt
文件,根据命名方案 ASyymm-sn
,yy
是当前年份,其名称用作格式 AS2204-1
的参考没有世纪,mm
是当前月份,sn
是当前月份的序列号。我尝试获取当前文件名并在年月不变的情况下将序列号递增1,将新文件名复制到剪贴板,然后重命名文本文件。
到目前为止,这是我的代码:
@echo off
set yy=%date:~12,2%
set mm=%date:~4,2%
set /a sn=0
for %%a in ('dir *.txt') do (set filename=%%a)
set Fmm=%filename:~5,2%
if %Fmm%==%mm% (set /a sn=sn+1) else (set /a sn=1)
echo AS%yy%%mm%^-%sn% |clip
ren "%filename%.txt" "AS%yy%%mm%^-%sn%.txt"
我无法获取分配给变量 filename
的文件名。
我的代码有什么问题,什么是正确的 FOR 循环?
可以使用以下批处理文件来完成此任务:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
for /F "tokens=1,2 delims=/" %%G in ('%SystemRoot%\System32\robocopy.exe "%SystemDrive%\|" . /NJH') do set "YearMonth=%%G%%H" & goto SearchFile
:SearchFile
set "SerialNumber=0"
set "FileNameScheme=AS%YearMonth:~2%-"
for %%G in ("%FileNameScheme%*.txt") do for /F "tokens=2 delims=-" %%H in ("%%~nG") do if %%H GTR !SerialNumber! (set "SerialNumber=%%H" & set "FileName=%%G")
set /A SerialNumber+=1
echo %FileNameScheme%%SerialNumber%| %SystemRoot%\System32\clip.exe
if defined FileName (
ren "%FileName%" "%FileNameScheme%%SerialNumber%.txt"
) else (
rem del /Q "AS????-*.txt" >nul 2>nul
echo %FileNameScheme%%SerialNumber%>"%FileNameScheme%%SerialNumber%.txt"
)
endlocal
前两行完全定义了所需的执行环境是:
- 命令回显模式关闭
- 命令扩展已启用
- 启用延迟变量扩展
请阅读我在 Time is set incorrectly after midnight 上的回答中的 使用 ROBOCOPY 获取当前 date/time 一章,以了解 FOR 的解释 命令行使用 ROBOCOPY 获取当前年份和月份独立于为使用的帐户配置哪个国家(地区)决定动态变量的日期格式 DATE
.
首先定义环境变量SerialNumber
,默认值为0
。
环境变量 FileNameScheme
以 AS
开始定义,没有世纪的当前年份始终为两位数,当前月份始终为两位数和 -
结果今天在字符串 AS2204-
.
命令FOR用于在当前目录(可以是任意目录)搜索一个或多个non-hidden匹配通配符模式 AS2204-*.txt
.
目前尚不清楚我的文件如何位于与通配符模式匹配的当前目录中 AS????-*.txt
。因此,编写的代码也适用于当前目录中与此通配符模式匹配的多个文件。
对于每个与当前年份和月份匹配的通配符模式的文件名,已经包含一个 FOR 循环用于获取连字符和文件扩展名之间的字符串,希望是始终是 0
到 2147483647
范围内的数字,不带前导零。
这个数字字符串与环境变量SerialNumber
的当前值进行比较。由于此数字比较,必须启用延迟变量扩展。如果当前文件的编号大于当前序列号,则继续使用较大的数字作为序列号,并将当前文件的名称赋值给环境变量FileName
.
请注意,GTR
不适用于文件中有前导零的数字,因为在这种情况下,数字将被解释为八进制而不是十进制数,这意味着 08
和 09
将被解释为无效的八进制数,在这种情况下使用值 0
进行数字比较。
默认值0
或匹配AS2204-*.txt
的最大文件数接下来使用算术表达式递增1。
出于任何目的将带有递增序列号的文件名不带文件扩展名复制到剪贴板。
如果真的找到了名称中包含当前年份和月份的文件,现在将此文件重命名为包含加一的序列号。否则,将使用新文件名创建一个新文件,并包含不带文件扩展名的文件名作为数据,例如 AS2204-1
.
有一行用命令 REM 注释掉,这将删除所有匹配通配符模式 AS????-*.txt
的文件,除了被命令 忽略的隐藏文件默认情况下 DEL 和 read-only 文件未被命令删除 DEL 默认情况下以及当前正在被应用程序打开的匹配文件。目前尚不清楚如何处理前一个月匹配此模式的其他文件。
如果当前目录中没有或始终只有一个文件匹配通配符模式 AS????-*.txt
,则批处理文件代码可以优化为以下命令行:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "tokens=1,2 delims=/" %%G in ('%SystemRoot%\System32\robocopy.exe "%SystemDrive%\|" . /NJH') do set "YearMonth=%%G%%H" & goto SearchFile
:SearchFile
set "SerialNumber=0"
set "FileNameScheme=AS%YearMonth:~2%-"
for %%G in ("%FileNameScheme%*.txt") do for /F "tokens=2 delims=-" %%H in ("%%~nG") do set "SerialNumber=%%H"
set /A SerialNumber+=1
echo %FileNameScheme%%SerialNumber%| %SystemRoot%\System32\clip.exe
if exist "AS????-*.txt" (
ren "AS????-*.txt" "%FileNameScheme%%SerialNumber%.txt"
) else (
echo %FileNameScheme%%SerialNumber%>"%FileNameScheme%%SerialNumber%.txt"
)
endlocal
不再需要延迟变量扩展,这使得批处理文件的处理速度稍微快了一点。带有一个或多个前导零的序列号仍然是一个问题,因为命令 SET 在计算算术表达式时将数字字符串也转换为整数,并将数字解释为八进制数数字字符串开头的字符 0
。
为了了解使用的命令及其工作原理,请打开 command prompt window,在其中执行以下命令,并仔细阅读为每个命令显示的所有帮助页面。
del /?
echo /?
endlocal /?
for /?
goto /?
if /?
rem /?
robocopy /?
set /?
setlocal /?
另请参阅:
- 关于 Using command redirection operators 的 Microsoft 文档
- Single line with multiple commands using Windows batch file 无条件命令运算符的解释
&
.
@echo off
setlocal
pushd "?:\whichever\directory\contains your\target files"
set "yy=%date:~12,2%"
set "mm=%date:~4,2%"
set "filename="
for /f %%a in ('dir /b /a-d /od AS%yy%%mm%-*.txt 2^>nul') do (set "filename=%%~na")
rem use this line if you use suppressed leading zero
if defined filename (set /a "sn=%filename:*-=%+1") else (set /a sn=1)
rem use this line if you use 2-digit
if defined filename (set /a "sn=1%filename:~-2%+1") else (set /a sn=101)
IF %sn% gtr 100 SET "sn=%sn:~-2%"
echo AS%yy%%mm%-%sn%
ren "whatever.txt" "AS%yy%%mm%-%sn%.txt"
POPD
goto :eof
setlocal
确保在批处理终止时删除环境更改(新变量)。
pushd
切换到指定目录。我不知道你的目录是什么。
语法 SET "var=value"
(其中值可能为空;在这种情况下 var
变为 undefined)用于确保任何杂散尾随空格不包括在分配的值中。
for /f
将dir
“报告”的每一行依次分配给%%a
。因此,filename
将仅设置为找到的文件名的名称部分 (%%~na
)。 dir /b
以基本形式(仅文件名)生成要处理的文件列表。 /a-d
排除目录名,/od
按日期顺序生成列表。文件掩码 AS%yy%%mm%-*.txt
要求匹配 AS
+thecurrentyearnumber+thecurrentmonthnumber+-
的所有 .txt
个文件,因此没有必要检查 year/month 部分。如果找不到与掩码匹配的文件名,2^>nul
会抑制错误消息。
如果找到文件名,filename
将被定义。这就是为什么它在 for
循环之前设置为 nothing(un 定义它)。
文件名必须按日期顺序生成,因为 ASyymm-10
将在默认 name-order 列表中排序 之前 ASyymm-2
。
嗯,我不知道您使用的是 1 位还是 2 位序列号 - 处理方式不同。
如果你使用第一个 if defined...
然后 sn
被设置为比 filename
多 1 的部分(当 -
之前的所有字符都存在时 filename
的那部分删除)或 1
如果没有找到先前的文件。
如果你使用第二个if defined...
那么sn
设置为比(1
+filename
的最后2个字符)多1或101
如果没有找到先前的文件,那么 ASyymm-07
将产生 sn=108
。这是必要的,因为在计算中批处理将 0
开头的数字字符串解释为 OCTAL。
如果结果>100,则使用sn
的最后2个字符。
我刚刚 echo
将所需的字符串输入到屏幕上。如果需要,回显到剪贴板。
嗯 - 重命名。不清楚要重命名为计算名称的文件是什么,所以我使用了whatever
。可能是一个名为 ASyymm.txt
的文件 - 如果是这样,请将 whatever
替换为 AS%yy%%mm%
.
popd returns到原目录。
对于大多数命令,可以通过执行 commandname /?
来获取文档,但有时可能会有点含糊。只需在 SO 中搜索示例即可。
首先感谢大家的回答! 我是这样做的 - 它工作正常,直到重命名部分不起作用 - 知道为什么吗?
set "yy=%date:~12,2%"
set "mm=%date:~4,2%"
set "filename=\root\*.txt"
for %%A in (%filename%) do (set x=%%~nA)
set Fmm=%x:~4,2%
set sn=%x:7.1%
if %Fmm%==%mm% (set /a sn=sn+1) else (set /a sn=1)
echo AS%yy%%mm%^-%sn% |clip
set newfilename=AS%yy%%mm%-%sn%.txt
set oldfilename=%x%.txt
ren %oldfilename% %newfilename%