There should be opened a command prompt window, ran set /?
and read the output usage help. It explains the syntax to (re)define environment variables. There are no spaces around =
. See also: Why is no string output with 'echo %var%' after using 'set var = text' on command line? There is also explained when and how to use delayed variable expansion on an IF and a FOR example. It is also described that the current values of environment variables should be referenced within an arithmetic expression with using just the variable names without using %
or !
around the variable names. An arithmetic expression is the argument string after option /A
of command SET.
应打开命令提示符窗口,运行set/?并阅读输出用法帮助。它解释了(重新)定义环境变量的语法。=周围没有空格。另请参阅:在命令行上使用‘set var=Text’后,为什么没有带有‘ECHO%var%’的字符串输出?还解释了何时以及如何在IF和A上使用延迟变量展开。还描述了在算术表达式中引用环境变量的当前值时,应该只使用变量名,而不使用%或!在变量名周围。算术表达式是命令集的OPTION/A后面的参数字符串。
There can be also executed in the command prompt window for /?
for getting output the usage help of command FOR which is obviously needed too.
也可以在命令提示符窗口中执行/?为了获得输出,显然也需要命令的用法帮助。
There are some important facts not described in the helps of command FOR and SET which are important on copying (or renaming or deleting or modifying) files in a directory with file extension kept and so matched also by the wildcard pattern.
在命令for和set的帮助中没有描述的一些重要事实对于复制(或重命名、删除或修改)目录中的文件非常重要,该目录保留了文件扩展名,因此也通过通配符模式进行匹配。
- FOR processes the list of matching file system entries which changes on each iteration of the loop because of the file copy operation which is very problematic here. For more details see: At which point does `for` or `for /R` enumerate the directory (tree)? The solution is getting first loaded all the wildcard pattern matching file names into the memory of
cmd.exe
processing the batch file before starting the copy operation loop.
- Enabled delayed variable expansion results in parsing a command line a second time by
cmd.exe
after loop variable references like %%F
are replaced by the string assigned to the loop variable. An exclamation mark in a file name is therefore interpreted as beginning/end of a delayed expanded variable reference. An exclamation mark is removed on being the last !
on odd number of !
in file name and everything between two !
in a file name is replaced by the value of the referenced environment variable respectively is removed from file name on no such environment variable exists at all. The result of this unwanted file name change caused by enabled delayed expansion is a not found file or a by mistake wrong selected file for the copy operation. See also: How does the Windows Command Interpreter (CMD.EXE) parse scripts?
Here is a batch file code which copies all non-hidden files with file extension .txt
even on containing on or more !
in file name.
这是一个批处理文件代码,它复制所有非隐藏文件的文件扩展名.txt,即使在包含上或更多!在文件名中。
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "Counter=-1"
for /F "eol=| delims=" %%I in ('dir *.txt /A-D-H /B /ON 2^>nul') do (
set "FileName=%%I"
set /A Counter+=2
setlocal EnableDelayedExpansion
copy /B /Y "!FileName!" "_!Counter!.txt" >nul
endlocal
)
endlocal
There is started by cmd.exe
processing the batch file one more command process in background with using %ComSpec% /c
and the command line within '
specified on the FOR /F command line appended as additional arguments. There is executed for that reason with Windows installed into C:\Windows
:
首先,cmd.exe在后台处理批处理文件另一个命令进程,并使用%ComSpec%/c和在for/F命令行上指定的‘内命令行作为附加参数。因此,将Windows安装到C:\WINDOWS:
C:\Windows\System32\cmd.exe /c dir *.txt /A-D-H /B /ON 2>nul
The internal command DIR of in background started cmd.exe
searches now
的内部命令DIR现在在后台启动了cmd.exe搜索
- in the current directory as defined by the process starting
cmd.exe
for processing the batch file which can be any directory and not necessarily the directory containing the batch file
- for just non-hidden files or non-hidden links to files because of option
/A-D-H
(attribute not directory and not hidden) including files with read-only attribute set
- matching the wildcard pattern
*.txt
in long or short 8.3 file name
- and outputs in bare format just the file names because of option
/B
- in alphabetical order by name because of option
/ON
.
An error message output by DIR to handle STDERR (standard error) on no matching file system entry found is suppressed by redirecting it to device NUL.
在未找到匹配的文件系统条目时,通过将其重定向到设备NUL,可以抑制由NTFS输出的用于处理STDERR(标准错误)的错误消息。
Read the Microsoft documentation about Using command redirection operators for an explanation of 2>nul
. The redirection operator >
must be escaped with caret character ^
on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir
command line with using a separate command process started in background.
有关2>nul的解释,请阅读有关使用命令重定向操作符的Microsoft文档。当Windows命令解释程序在执行命令之前处理此命令行时,必须使用插入字符^将重定向操作符>转义,才能将命令行解释为文字字符。Windows命令解释程序将使用后台启动的单独命令进程执行嵌入的目录命令行。
The Windows Command Processor processing the batch file captures everything written to handle STDOUT (standard output) of the background command process. Once DIR finished resulting in close of the background cmd.exe
because of option /c
, the internal command FOR of the batch file processing cmd.exe
starts the processing of the list of file names which is loaded now into the memory of cmd.exe
processing the batch file. The file copy operations in same directory do not change anymore the file names list processed by FOR.
处理批处理文件的Windows命令处理器捕获为处理后台命令进程的STDOUT(标准输出)而编写的所有内容。由于选项/c而导致后台cmd.exe关闭的DIR完成后,批处理文件处理cmd.exe的内部命令将开始处理现在加载到处理批处理文件的cmd.exe内存中的文件名列表。同一目录中的文件复制操作不再更改for处理的文件名列表。
The FOR /F option delims=
defines an empty list of delimiters to turn off the default line splitting behavior on normal spaces and horizontal tabs to get the full file name in a line assigned to the specified loop variable I
and not just the first space/tab separated string as by default.
For/F选项delims=定义空分隔符列表,以关闭正常空格和水平制表符上的默认拆行行为,以获取指定循环变量i所在行中的完整文件名,而不是默认情况下第一个空格/制表符分隔的字符串。
The FOR /F option eol=|
defines the vertical bar as end of line character replacing the default ;
which prevents ignoring a file name beginning with a semicolon. The Microsoft documentation about Naming Files, Paths, and Namespaces describes which characters are not allowed in file names on Windows file systems like NTFS, FAT32 or exFAT. One of those characters should be used as end of line character.
For/F选项eol=|将竖线定义为行尾字符替换默认字符;这可防止忽略以分号开头的文件名。Microsoft文档《关于命名文件、路径和命名空间》介绍了在NTFS、FAT32或exFAT等Windows文件系统上的文件名中不允许使用的字符。这些字符中的一个应用作行尾字符。
It is necessary to assign first the file name with file extension to an environment variable and increment the value of the environment variable Counter
by two. Then delayed variable expansion is enabled for copying the file with referencing the file name assigned to the environment variable FileName
and the value of the Counter
environment variable. The previous environment must be restored next with the command ENDLOCAL as otherwise a stack overflow could occur during the copy operations. Read this answer for details about the commands SETLOCAL and ENDLOCAL with a full description what happens on each execution of SETLOCAL and ENDLOCAL in memory of cmd.exe
processing the batch file.
需要首先将文件名和文件扩展名分配给环境变量,然后将环境变量Counter的值增加2。然后,通过引用分配给环境变量FileName的文件名和Counter环境变量的值,启用延迟变量扩展以复制文件。接下来必须使用命令ENDNOW恢复以前的环境,否则在复制操作期间可能会发生堆栈溢出。请阅读此答案,了解有关命令SETSTARY和ENDSTARY的详细信息,并完整描述在处理批处理文件的Xbox.exe内存中每次执行SETSTARY和ENDSTARY时会发生什么。
NOTE:
注:
It would be a very good idea to copy the files into a different directory than the current directory like the parent directory of the current directory by using the command line:
最好使用命令行将文件复制到与当前目录不同的目录中,如当前目录的父目录:
copy /B /Y "!FileName!" "..\_!Counter!!FileExt!" >nul
The code above is still a problem if the current directory contains a.txt
, b.txt
, c.txt
, ... but also already _1.txt
, _3.txt
, _5.txt
, ... from a previous execution of the batch file. Copying the files into a different directory would avoid that problem as well as the usage of the following code:
如果当前目录包含.txt、b.txt、c.txt、...而且已经_1.txt,_3.txt,_5.txt,...来自批处理文件的先前执行。将文件复制到不同的目录可以避免该问题以及以下代码的使用:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "Counter=-1"
for /F "eol=| delims=" %%I in ('dir *.txt /A-D-H /B /ON 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /V /X "_[0123456789][0123456789]*\.txt"') do (
set "FileName=%%I"
set /A Counter+=2
setlocal EnableDelayedExpansion
copy /B /Y "!FileName!" "_!Counter!.txt" >nul
endlocal
)
endlocal
The command FINDSTR is used for filtering out all file names of which entire name is matched case-insensitive by the regular expression which searches for an underscore followed by one or more digits and next a literally interpreted dot and the string txt
.
FINDSTR命令用于通过正则表达式筛选出全名匹配且不区分大小写的所有文件名,正则表达式搜索下划线,后跟一个或多个数字,然后是字面解释的圆点和字符串txt。
To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.
要了解使用的命令及其工作原理,请打开命令提示符窗口,在那里执行以下命令,并完整而仔细地阅读显示的每个命令的帮助页面。
cmd /?
copy /?
dir /?
echo /?
endlocal /?
findstr /?
for /?
set /?
setlocal /?
first of all you have a typo in your script, just try to remove the spaces around the equal sign in this line set COUNTER = %C%
and better to add double quotes around %%F
and _!C!.txt
to handle file names with spaces correctly, and also change %C%
to !C!
to enable delayed expansion inside the loop!
首先,您的脚本中有一个拼写错误,只需尝试删除此行中等号周围的空格set count=%C%,最好在%%F和_!c!.txt两边添加双引号,以正确处理带有空格的文件名,并将%C%更改为!c!以启用循环内的延迟扩展!
so check this out :
所以,看看这个:
@echo off
setlocal enableDelayedExpansion
set COUNTER=-1
for %%F in (*.txt) do (
set /A C=%COUNTER%+2
rem echo !C!
copy "%%F" "_!C!.txt"
set COUNTER=!C!
)
Here is what your code should have looked like:
下面是您的代码应该是什么样子:
@Echo Off
SetLocal EnableExtensions EnableDelayedExpansion
Set "Counter=-1"
For %%G In ("*.txt") Do (
Set /A Counter += 2
Rem Echo !Counter!
Copy /Y "%%G" "_!Counter!%%~xG"
)
EndLocal
The setlocal enableDelayedExpansion
command is used to enable delayed variable expansion with !
instead of %
for variable access, but you are still using %
for variable access in your script. You should use !
instead of %
if you intend to use delayed variable expansion.
Setlocal enableDelayedExpansion命令用于通过!启用延迟变量扩展!变量访问权限不是%,但在脚本中变量访问权限仍然使用%。你应该用!如果您打算使用延迟变量扩展,则不使用%。
There is a space before and after the equals sign in the set COUNTER = %C%
line, which is incorrect. Batch script variable assignment should not have spaces around the equals sign.
SET COUNTER=%C%行中的等号前后有一个空格,这是不正确的。批处理脚本变量赋值不应包含等号周围的空格。
@echo off
setlocal enableDelayedExpansion
set COUNTER=-1
for %%F in (*.txt) do (
set /A C=!COUNTER! + 2
rem echo !C!
copy %%F _!C!.txt
set COUNTER=!C!
)
更多回答
you don't even need the c
variable. Increase the counter
directly: set /a counter+=2
(and copy"%%F" "_!counter!.txt"
Also it might be a good idea to not rename files already starting with _
: `for /f "delims=" %%F in ('dir /b /a-d *.txt ^| findstr /bv "_"') do (
您甚至不需要c变量。直接增加计数器:设置/a计数器+=2(并复制“%%F”“_!count!.txt”此外,最好不要重命名已以_:`for/f“delims=”%%F in(‘dir/b/a-d*.txt^|findstr/bv“_”’)DO(
我是一名优秀的程序员,十分优秀!