2009年7月4日星期六

DOS for command


For

Runs a specified command for each file in a set of files.

Syntax

for {%variable|%%variable} in (set) do command [ CommandLineOptions]

Parameters

{%variable|%%variable} : Required. Represents a replaceable parameter. Use %variable to carry out for from the command prompt. Use %%variable to carry out the for command within a batch file. Variables are case-sensitive and must be represented with an alpha value, such as %A, %B, or %C.

(set) : Required.
Specifies one or more files, directories, range of values, or text
strings that you want to process with the specified command. The
parentheses are required.

command : Required.
Specifies the command that you want to carry out on each file,
directory, range of values, or text string included in the specified (set).

CommandLineOptions : Specifies any command-line options that you want to use with the specified command.

/?: Displays help at the command prompt.



Remarks

Using for

You can use the for command within a batch file or directly from the command prompt.

Using batch parameters

The following attributes apply to the for command:

The for command replaces %variable or %%variable with each text string in the specified set until the command processes all of the files.

For variable names are case-sensitive, global, and no more than 52 total can be active at any one time.

To avoid confusion with the batch parameters %0 through %9, you can use any character for variable except the numerals 0 through 9. For simple batch files, a single character such as %%f works.

You can use multiple values for variable in complex batch files to distinguish different replaceable variables.

Specifying a group of files

The set
parameter can represent a single group of files or several groups of
files. You can use wildcards (that is, * and ?) to specify a file set.
The following are valid file sets:

(*.doc)

(*.doc *.txt *.me)

(jan*.doc jan*.rpt feb*.doc feb*.rpt)

(ar??1991.* ap??1991.*)

When you use the for command, the first value in set replaces %variable or %%variable,
and then the specified command processes this value. This continues
until all of the files (or groups of files) that correspond to the set value are processed.

Using the in and do keywords

In and do are not parameters, but you must use them with for. If you omit either of these keywords, an error message appears.

Using additional forms of for

If command extensions are enabled (that is, the default), the following additional forms of for are supported:

Directories only

If set contains wildcards (* and ?), the specified command executes for each directory (instead of a set of files in a specified directory) that matches set. The syntax is:

for /D {%% | %}variable in (set) do command [CommandLineOptions]

Recursive

Walks the directory tree rooted at [Drive:]Path, executing the for statement in each directory of the tree. If no directory is specified after /R, the current directory is assumed. If set is just a single period (.), it only enumerates the directory tree. The syntax is:

for /R [[Drive :]Path] {%% | %}variable in (set) do command [CommandLineOptions]

Iterating a range of values

Use an iterative variable to set the starting value (start#) and then step through a set range of values until the value exceeds the set ending value (end#). /L will execute the iterative by comparing start# with end#. If start# is less than end# the command will execute. When the iterative variable exceeds end# the command shell exists the loop. You can also use a negative step#
to step through a range in decreasing values. For example, (1,1,5)
generates the sequence 1 2 3 4 5 and (5,-1,1) generates the sequence (5
4 3 2 1). The syntax is:

for /L {%% | %}variable in (start#,step#,end#) do command [CommandLineOptions]

Iterating and file parsing

Use
file parsing to process command output, strings and file content. Use
iterative variables to define the content or strings you want to
examine and use the various ParsingKeywords options to further modify the parsing. Use the ParsingKeywords token option to specify which tokens should be passed as iterator variables. Note that when used without the token option, /F will only examine the first token.

File
parsing consists of reading the output, string or file content,
breaking it up into individual lines of text and then parsing each line
into zero or more tokens. The for loop is then called with the iterator variable value set to the token. By default, /F passes the first blank separated token from each line of each file. Blank lines are skipped. The different syntaxes are:

for /F ["ParsingKeywords"] {%% | %}variable in (filenameset) do command [CommandLineOptions]

for /F ["ParsingKeywords"] {%% | %}variable in ("LiteralString") do command [CommandLineOptions]

for /F ["ParsingKeywords"] {%% | %}variable in ('command') do command [CommandLineOptions]

The filenameset argument specifies one or more file names. Each file is opened, read and processed before going on to the next file in filenameset. To override the default parsing behavior, specify "ParsingKeywords". This is a quoted string that contains one or more keywords to specify different parsing options.

If you use the usebackq option, use one of the following syntaxes:

for /F ["usebackqParsingKeywords"] {%% | %}variable in ("filenameset") do command [CommandLineOptions]

for /F ["usebackqParsingKeywords"] {%% | %}variable in ('LiteralString') do command [CommandLineOptions]

for /F ["usebackqParsingKeywords"] {%% | %}variable in (`command`) do command [CommandLineOptions]

The following table lists the parsing keywords that you can use for ParsingKeywords.

KeywordDescription

eol=c

Specifies an end of line character (just one character).

skip=n

Specifies the number of lines to skip at the beginning of the file.

delims=xxx

Specifies a delimiter set. This replaces the default delimiter set of space and tab.

tokens=x,y,m-n

Specifies which tokens from each line are to be passed to the for body for each iteration. As a result, additional variable names are allocated. The m-n form is a range, specifying the mth through the nth tokens. If the last character in the tokens=
string is an asterisk (*), an additional variable is allocated and
receives the remaining text on the line after the last token that is
parsed.

usebackq

Specifies that you can use quotation marks to quote file names in filenameset, a back quoted string is executed as a command, and a single quoted string is a literal string command.

Variable substitution

Substitution modifiers for for variable references have been enhanced. The following table lists optional syntax (for any variable I).

Variable with modifierDescription

%~I

Expands %I which removes any surrounding quotation marks ("").

%~fI

Expands %I to a fully qualified path name.

%~dI

Expands %I to a drive letter only.

%~pI

Expands %I to a path only.

%~nI

Expands %I to a file name only.

%~xI

Expands %I to a file extension only.

%~sI

Expands path to contain short names only.

%~aI

Expands %I to the file attributes of file.

%~tI

Expands %I to the date and time of file.

%~zI

Expands %I to the size of file.

%~$PATH:I

Searches
the directories listed in the PATH environment variable and expands %I
to the fully qualified name of the first one found. If the environment
variable name is not defined or the file is not found by the search,
this modifier expands to the empty string.

The following table lists modifier combinations that you can use to get compound results.

Variable with combined modifiersDescription

%~dpI

Expands %I to a drive letter and path only.

%~nxI

Expands %I to a file name and extension only.

%~fsI

Expands %I to a full path name with short names only.

%~dp$PATH:I

Searches
the directories listed in the PATH environment variable for %I and
expands to the drive letter and path of the first one found.

%~ftzaI

Expands %I to an output line that is like dir.

In the above examples, you can replace %I and PATH by other valid values. A valid for variable name terminates the %~ syntax.

By use uppercase variable names such as %I, you can make your code more readable and avoid confusion with the modifiers, which are not case-sensitive.

Parsing a string

You can use the for /F parsing logic on an immediate string, by wrapping the filenameset between the parentheses in single quotation marks (that is, 'filenameset'). Filenameset is treated as a single line of input from a file, and then it is parsed.

Parsing output

You can use the for /F command to parse the output of a command by making the filenameset
between the parenthesis a back quoted string. It is treated as a
command line, which is passed to a child Cmd.exe and the output is
captured into memory and parsed as if it were a file.

Examples

To use for in a batch file, use the following syntax:

for %%variable in (set) do command [CommandLineOptions]

To
display the contents of all the files in the current directory that
have the extension .doc or .txt using the replaceable variable %f, type:

for %f in (*.doc *.txt) do type %f

In the preceding example, each file that has the .doc or .txt extension in the current directory is substituted for the %f variable until the contents of every file are displayed. To use this command in a batch file, replace every occurrence of %f with %%f. Otherwise, the variable is ignored and an error message is displayed.

To parse a file, ignoring commented lines, type:

for /F "eol=; tokens=2,3* delims=," %i in (myfile.txt) do @echo %i %j %k

This
command parses each line in Myfile.txt, ignoring lines that begin with
a semicolon and passing the second and third token from each line to
the FOR body (tokens are delimited by commas or spaces). The body of the FOR statement references %i to get the second token, %j to get the third token, and %k
to get all of the remaining tokens. If the file names that you supply
contain spaces, use quotation marks around the text (for example, "File Name"). To use quotation marks, you must use usebackq. Otherwise, the quotation marks are interpreted as defining a literal string to parse.

%i is explicitly declared in the FOR statement, and %j and %k are implicitly declared by using tokens=. You can specify up to 26 tokens using tokens=, provided that it does not cause an attempt to declare a variable higher than the letter 'z' or 'Z'.

To parse the output of a command by placing filenameset between the parentheses, type:

for /F "usebackq delims==" %i IN (`set`) DO @echo %i

This example enumerates the environment variable names in the current environment.

========================================================================

http://qzone.qq.com/blog/952345670-1209611526

以前常觉得DOS的命令行功能太弱,无法象UNIX一样可以用命令行完成非常复杂的操作。实际上,当MS从WIN2K开始将命令行增强后,已经借鉴了相当
多UNIX的优点,虽然还无法做到象UNIX那么灵活,但已可完成绝大多数的任务,比如用&&和||连接两个(或更多)命令,由前一个的
返回值来决定下一个是否执行,等等。而在这些增强中,最明显的,就是FOR命令。

举个例子,用适当的参数,可用FOR命令将 date /t 的输出 从 "Sat 07/13/2002" 变成你想要的格式,比如, "2002-07-13":

c:>for /f "tokens=2,3,4 delims=/ " %a in ('date /t') do @echo %c-%a-%b
2002-07-13

该例将在(3)中详细说明。

0. 基本应用

简单说,FOR是个循环,可以用你指定的循环范围生成一系列命令。最简单的例子,就是人工指定循环范围,然后对每个值执行指定的命令。例如,想快速报告每个硬盘分区的剩余空间:

for %a in (c: d: e: f do @dir %a | find "bytes free"
将输出:
8 Dir(s) 1,361,334,272 bytes free
15 Dir(s) 8,505,581,568 bytes free
12 Dir(s) 12,975,149,056 bytes free
7 Dir(s) 11,658,854,400 bytes free

用它可以使一些不支持通配符的命令对一系列文件进行操作。在WIN9X中,TYPE命令(显示文件内容)是不支持*.txt这种格式的(WIN2K开始TYPE已支持通配)。遇到类似情况就可以用FOR:

for %a in (*.txt) do type %a

这些还不是FOR最强大的功能。我认为它最强大的功能,表现在以下这些高级应用:
1. 可以用 /r 参数遍历整个目录树
2. 可以用 /f 参数将文本文件内容作为循环范围
3. 可以用 /f 参数将某一命令执行结果作为循环范围
4. 可以用 %~ 操作符将文件名分离成文件名、扩展名、盘符等独立部分

现分别举例说明如下:
1. 用 /r 遍历目录树

用 *.* 或 *.txt 等文件名通配符作为 for /r
的循环范围时,可以对当前目录下所有文件(包括子目录里面的文件)进行操作。举个例子,你想在当前目录的所有txt文件(包括子目录)内容中查
找"bluebear"字样,但由于find本身不能遍历子目录,所以我们用for:

for /r . %a in (*.txt) do @find "bluebear" %a

find 前面的 @ 只是让输出结果不包括 find 命令本身。这是DOS很早就有的功能。和FOR无关。

用 . 作为循环范围时,for 只将子目录的结构(目录名)作为循环范围,而不包括里面的文件。有点象 TREE 命令,不过侧重点不同。TREE
的重点是用很漂亮易读的格式输出,而FOR的输出适合一些自动任务,例如,我们都知道用CVS管理的项目中,每个子目录下都会有一个CVS目录,有时在软
件发行时我们想把这些CVS目录全部去掉:

for /r . %a in (.) do @if exist %aCVS rd /s /q %aCVS

先用 if exist 判断一下,是因为 for 只是机械的对每个目录进行列举,如果有些目录下面没有CVS也会被执行到。用 if exist 判断一下比较安全。
这种删除命令威力太大,请小心使用。最好是在真正执行以上的删除命令前,将 rd /s /q 换成 @echo 先列出要删出的目录,确认无误后再换回rd /s /q:

for /r . %a in (.) do @if exist %aCVS @echo %aCVS

可能目录中会多出一层 ".",比如 c:projrelease.CVS ,但不会影响命令的执行效果。

2. 将某一文件内容或命令执行结果作为循环范围:
假如你有一个文件 todel.txt,里面是所有要删除的文件列表,现在你想将里面列出的每个文件都删掉。假设这个文件是每个文件名占一行,象这样:
c:tempa1.txt
c:tempa2.txt
c:tempsubdirb3.txt
c:tempsubdirb4.txt

那么可以用FOR来完成:
for /f %a in (todel.txt) do del %a

这个命令还可以更强大。比如你的 todel.txt 并不是象上面例子那么干净,而是由DIR直接生成,有一些没用的信息,比如这样:

Volume in drive D is DATA
Volume Serial Number is C47C-9908

Directory of D:tmp
09/26/2001 12:50 PM 18,426 alg0925.txt
12/02/2001 04:29 AM 795 bsample.txt
04/11/2002 04:18 AM 2,043 invitation.txt
4 File(s) 25,651 bytes
0 Dir(s) 4,060,700,672 bytes free

for 仍然可以解出其中的文件名并进行操作:
for /f "skip=5 tokens=5" %a in (todel.txt) do @if exist %a DEL %a

当然,上面这个命令是在进行删除,如果你只是想看看哪些文件将被操作,把DEL换成echo:

for /f "skip=5 tokens=5" %a in (todel.txt) do @if exist %a echo %a

你将看到:
alg0925.txt
bsample.txt
invitation.txt

skip=5
表示跳过前5行(就是DIR输出的头部信息),tokens=5表示将每行的第5列作为循环值放入%a,正好是文件名。在这里我加了一个文件存在判断,是
因为最后一行的"free"刚好也是第5列,目前还想不出好的办法来滤掉最后两行,所以检查一下可保万无一失。

3. 可以用 /f 参数将某一命令执行结果作为循环范围
非常有用的功能。比如,我们想知道目前的环境变量有哪些名字(我们只要名字,不要值)。可是SET命令的输出是“名字=值”的格式,现在可以用FOR来只取得名字部分:

FOR /F "delims==" %i IN ('set') DO @echo %i

将看到:
ALLUSERSPROFILE
APPDATA
CLASSPATH
CommonProgramFiles
COMPUTERNAME
ComSpec
dircmd
HOMEDRIVE
......

这里是将set命令执行的结果拿来作为循环范围。delims==表示用=作为分隔符,由于FOR /F默认是用每行第一个TOKEN,所以可以分离出变量名。如果是想仅列出值:

FOR /F "delims== tokens=2" %i IN ('set') DO @echo %i
tokens=2和前例相同,表示将第二列(由=作为分隔符)作为循环值。

再来个更有用的例子:
我们知道 date /t (/t表示不要询问用户输入)的输出是象这样的:
Sat 07/13/2002

现在我想分离出日期部分,也就是13:
for /f "tokens=3 delims=/ " %a in ('date /t') do @echo %a

实际上把 tokens后面换成1,2,3或4,你将分别得到Sat, 07, 13和2002。注意delims=/后面还有个空格,表示/和空格都是分隔符。由于这个空格delims必须是/f选项的最后一项。

再灵活一点,象本文开头提到的,将日期用2002-07-13的格式输出:

for /f "tokens=2,3,4 delims=/ " %a in ('date /t') do @echo %c-%a-%b

当tokens后跟多个值时,将分别映射到%a, %b, %c等。实际上跟你指定的变量有关,如果你指定的是 %i, 它们就会用%i, %j, %k等。
灵活应用这一点,几乎没有做不了的事。

4. 可以用 %~ 操作符将文件名分离成文件名、扩展名、盘符等独立部分
这个比较简单,就是说将循环变量的值自动分离成只要文件名,只要扩展名,或只要盘符等等。
例:要将 c:mp3下所有mp3的歌名列出,如果用一般的 dir /b/s 或 for /r ,将会是这样:

g:mp3Archived5-18-01-A游鸿明-下沙游鸿明-01 下沙.mp3
g:mp3Archived5-18-01-A游鸿明-下沙游鸿明-02 21个人.mp3
......
g:mp3Archived5-18-01-A王菲-寓言王菲-阿修罗.mp3
g:mp3Archived5-18-01-A王菲-寓言王菲-彼岸花.mp3
g:mp3Archived5-18-01-A王菲-寓言王菲-不爱我的我不爱.mp3
......

如果我只要歌名(不要路径和".mp3"):

游鸿明-01 下沙
游鸿明-02 21个人
......
王菲-阿修罗
王菲-彼岸花
王菲-不爱我的我不爱
......

那么可以用FOR命令:

for /r g:mp3 %a in (*.mp3) do @echo %~na

凡是 %~ 开头的操作符,都是文件名的分离操作。具体请看 for /? 帮助。

本文举的例子有些可能没有实际用处,或可用其它办法完成。仅用于体现FOR可以不借助其它工具,仅用DOS命令组合,就可完成相当灵活的任务。

===============================================================
http://www.dreammx.com/BBS/viewthread.php?tid=4786
一.for命令格式

对一组文件中的每个文件运行指定的命令。

可以在批处理程序中或直接从命令提示符使用 for 命令。

要在批处理程序中使用 for 命令,请使用以下语法:

for %%variable in (set) docommand [command-parameters]

要在命令提示符下使用 for,请使用以下语法: (区别就是在于变量前的%)

for %variable in (set) do command [command-parameters]

参数

%%variable 或 %variable

代表可替换的参数。for 命令使用在 set 中指定的每个文本字符串替换 %%variable(或 %variable),直到此命令(在
command-parameters 中指定)处理所有的文件为止。使用 %% variable 在批处理程序中执行 for 命令。使用 %
variable 通过命令提示符执行 for 命令。变量名区分大小写。

(set)

指定要用指定的命令处理的一个或多个文件或文本字符串。需要括号。

command

指定要在指定的 set 所包含的每个文件上执行的命令。

command-parameters

指定要用于指定命令(如果指定的命令要使用任何参数或开关)的任何参数或开关。

二.for 命令的其他形式

如果启用了命令扩展,将支持如下 for 命令的其他格式:

只限于目录

for /d [%% | %]variable in (set) docommand [command-parameters]

如果 set 包含通配符(* 和 ?),则指定与目录名匹配,而不是文件名。

递归

for /r [[drive :]path] [%% | %]variable in (set) docommand [command-parameters]

进入根目录树[drive:]path,在树的每个目录中执行 for 语句。如果在 /r 后没有指定目录,则假定为当前目录。如果 set 只是一个句号 (.) 字符,则只列举目录树。

迭代

for /l [%% | %]variable in (start,step,end) do command [command-parameters]

集合是一系列按步长量划分的、从头到尾的数字。这样,(1,1,5) 将生成序列 1 2 3 4 5,而 (5,-1,1) 将生成序列 (5 4 3 2 1)。

文件解析

for /f ["options"] [%% | %]variable in (filenameset) do command [command-parameters]

for /f ["options"] [%% | %]variable in ("literal string") do command[command-parameters]

for /f ["options"] [%% | %]variable in (‘command‘) do command [command-parameters]

或者,如果出现 usebackq 选项:

for /f ["options"] [%% | %]variable in (filenameset) do command [command-parameters]

for /f ["options"] [%% | %]variable in (‘literal string‘) do command [command-parameters]

for /f ["options"] [%% | %]variable in (`command`) docommand [command-parameters]

三.for使用范例

显示目录中的文件

假定要使用 type 命令显示当前目录中扩展名为 .doc 或 .txt 的所有文件内容。为此,为了使用可替换变量 %f,请在命令提示符后键入以下命令:

for %f in (*.doc *.txt) do type %f

在此范例中,当前目录中扩展名为 .doc 或 .txt 的每个文件都被替代为变量 %f ,直到每个文件的内容都显示为止。要在批处理文件中使用该命令,只需使用 %%f 替换 %f 的事件。否则,windows 2000 将忽略变量并显示错误信息。

重定向输出到打印机

windows 2000 支持在指定命令中使用的命令开关、管道和重定向。例如,要将上例中的输出重定向到 prn(默认的打印机端口),可以键入下面的命令:

for %f in (*.doc *.txt) do type %f >; prn:

解析文件

要分析文件并忽略注释行,可以使用:

for /f "eol=; tokens=2,3* delims=," %i in (myfile.txt) do @echo %i %j %k

这将解析 myfile.txt 文件的每一行,忽略以分号开头的行,将第二和第三个令牌环传递到 for
正文中,令牌环通过逗号和/或空格分隔。注意:for 语句引用 %i 以获得第二个令牌,引用 %j 以获得第三个令牌,引用 %k
以获得第三个令牌之后其余的全部令牌。对于包含空格的文件名,必须在文件名两端加上双引号。为了以此方式使用双引号,还需要使用 usebackq
选项,否则双引号将被解释为定义了要解析的文字字符串。

%i 在 for 语句中明确声明,并且 %j 和 %k 使用 tokens= option 隐含声明。如果它不会导致尝试声明高于字母“z”或“z”的某个变量,使用 tokens= 行可以指定最多 26 个标记。

记住,for 变量名区分大小写、全局的,并且每次总体不超过 52 个是活动的。

解析字符串

也可以对相邻的字符串使用 for /f 分析逻辑,方法是使括号之间的 filenameset 为一个用单引号引起来的字符串。将它当作文件的单行输入并进行解析。

解析输出

最后,可以使用 for /f 命令来对命令的输出结果进行解析。通过使 filenameset 在反引字符串的括号之间来执行此操作。将它作为命令行,此命令被传递给子 cmd.exe 并将输出捕获到内存并进行解析,就象它是一个文件一样。因此,下面的范例:

for /f "usebackq delims==" %i in (`set`) do @echo %i

这将列举当前环境中的环境变量名。



四.针对网络探测时使用for命令

1. for /f “tokens=1,2*” %i in (filename.txt) do net use \\target\ipc$ %i /u:%j

呵呵,首先/f的参数的含意是解析文件的意思。这将解析 filename.txt 文件的每一行,将第一和第二个令牌环传递到 for
正文中,令牌环通过逗号和/或空格分隔。注意:for 语句引用 %i 以获得第一个令牌,引用 %j
以获得第二个令牌。(注:我也不大明白令牌在这具体意思,不过可以确定的就是第一个令牌就是每行的第一个字符窜,第二个令牌就是用空格分开的第二个字符
窜。呵呵,至于*的意思是这样的,在令牌 =
字符串中最后一个字符是星号,则将分配附加的变量,并在解析最后一个令牌后在行上接收剩余的文本。当然如果txt文本的格式如下,只有每行只有两个字符窜
的话就可以省去了。)

filename.txt的内容格式如下:

password username

password administrator

password administrator

password administrator

in ()里添写上需要解析的文本文件名。

do后面则添加需要执行的命令如net use 、net user等。

(是不是有点对administrator暴力跑ipc%,获得密码的味道啊?呵呵,就是字典做的有点累。)



2. for /l %i in(1,1,254) do net use \\x.x.x.%i\ipc$ “” /user:“”

/l这个参数是用来控制迭代的。

in()里的集合是一系列按步长量划分的、从头到尾的数字。这样,(1,1,5) 将生成序列 1 2 3 4 5,而 (5,-1,1) 将生成序列 (5 4 3 2 1)。

do 后的用法同上。看看也能明白意思了吧。写这篇文章也没什么特别意思,只是怕自己看到的好东西会忘掉。呵呵,不过总是有启发的,不是吗?

其实for用法有很多啊。比如用来添加权限相同的帐号。你就可以先在记事本里写好了运行一个for命令不就ok了。不用一个一个的添加,那样的话还不要累死。当然do后面可以跟更多的参数,可以干更多的类似暴力的事喔。嘿嘿.....

=======================================================================
willsort老大上面的帖子,对于新手来说比较难理解。不过没关系,我们先分析一个例子,同样是引用willsort老大的。本例启用了变量延迟,是个正确的例子!
例1:

CODE: [Copy to clipboard]



@echo off & setlocal EnableDelayedExpansion
for /f "tokens=* delims=" %%i in ("Hello world.") do (
set n=%%i
set n=!n:ld.=t!
set n=!n:o w= S!
set n=!n:He=Wi!
echo !n!
)
pause
将上面代码保存为.bat双击执行后会显示“Will Sort”字符串,下面将讲解每个语句的意思:
1.@echo off & setlocal EnableDelayedExpansion
关闭命令回显,并启用变量延迟

2.for /f "tokens=* delims=" %%i in ("Hello world.") do (
for命令及其参数的使用,请大家在论坛里搜索相关字眼。限于篇幅问题,这里不作讨论。如果此时你不明白它的意思,那么你就当它的作用是把字符串“Hello world.”赋值给%%i好了,当然这只是权宜之计,以后一定要学习for的使用!

3.set n=%%i
把%%i的值(即Hello world.)赋予给变量n,这个大家都知道吧

4.set n=!n:ld.=t!

里要讲讲set替换字符的功能了。这个语句的意思是,先获取变量n的值(此时n的值是“Hello
world.”),然后将字符“t”替换字符“ld.”,然后再将替换后的结果再次赋值给变量n(此时n的值变为“Hello
wort”)。至于set替换字符的编写格式,大家可以在CMD键入“set/?”找到“%PATH:str1=str2%”这段有说明

5.set n=!n:o w= S!
意思和上句一样,只是替换和被替换的内容不同。它是将“ S”替换“o w”(注意S前面和w前面都有个空格),其实willsort老大是想证明set替换字符是支持句点和空格的(第4句“ld”后面有个.)。此时n的值为“Hell Sort”

6.set n=!n:He=Wi!
这句不用说了吧,执行完这句后n的值为“Will Sort”

7.echo !n!
显示变量n的值

需要注意的是,一旦启用了变量延迟,就要用!号把变量括起来,而不能用%号。

好了,每句的意思已经说完了,下面要讲本帖真正要讨论的变量延迟的问题。


里又要引用Will
Sort老大的说明:当CMD读取for语句时,其后用一对圆括号闭合的所有语句将一同读取,并完成必要的预处理工作,这其中就包括环境变量的扩展,所以
在for中的所有语句执行之前,所有的环境变量都已经被替换为for之前所设定的值,从而成为一个字符串常量,而不再是变量。

而为了能够在for语句内部感知环境变量的动态变化,CMD设计了延迟的环境变量扩展特性,也就是说,当CMD读取了一条完整的语句之后,它不会立即执行变量的扩展行为,而会在某个单条语句执行之前再进行扩展,也就是说,这个扩展行为被“延迟”了。

总的来说是,在没有启用变量延迟的情况下,凡是在括号内(即do里面)的变量,在执行for语句之前,就已经被替换成for语句之前其它命令对该变量所赋予的值。这句话不懂没关系,下面再看一个例子,看完你就会明白。
例2:
CODE: [Copy to clipboard]



@echo off
for /f "tokens=* delims=" %%i in ("Hello world.") do (
set n=%%i
set n=%n:ld.=t%
set n=%n:o w= S%
set n=%n:He=Wi%
echo %n%
)
pause
这和前面的例子差不多,只是所有!号都换成%号,这是个错误的例子。因为它没有启用变量延迟,也没有使用!号把变量括起来。我们看到它的执行结果是显示“ECHO 处于关闭状态”。

为什么会这样呢?原因是,在没有启用变量延迟的情况下,凡是在括号内(即do里面)的变量,在执行for语句之前,就已经被替换成for语句之前其它命令对该变量所赋予的值。
则是说在本例中的以下几句
set n=%%i
set n=%n:ld.=t%
set n=%n:o w= S%
set n=%n:He=Wi%
echo %n%

一句能正常执行并达到它的目的,因为它只是单纯地将%%i的值赋予给变量n,所以没有任何问题。其它几句属这样情况:早在for语句执行前,CMD就急不
切待地将这几句里面的所有变量n一同执行替换行为,替换为for之前,其它命令对n所设置的值,从而使n变成一个常量。但在本例中,for语句之前只有
@echo off这句,并没有其它命令对n作过任何赋值行为,所以在for之前,变量n的值为空值。即是说,set n=%n:ld.=t%
这句里面的变量n,在CMD读取(注意是读取不是执行)完整个for语句后(这时还未轮到set执行自己的任务),就立刻被替换为一个空值,一个空值里面
没有任何东西,所以就不存在一字符替换另一字符这种说法(没有东西怎么替换?)。最终到执行set
n=%n:ld.=t%语句时,它只是获取一个空值,再给变量n赋予空值而已。其它几句也是一样原理。

所以,最后echo %n%的时候变量n还是个空值,而echo命令没有东西可以显示,就只有显示“ECHO 处于关闭状态”这句来说明自己的状态

通过这个例子的说明,相信大家已经知道变量延迟的作用吧!我们再回头来看看例1。
启用变量延迟后,在执行
set n=!n:ld.=t!
set n=!n:o w= S!
set n=!n:He=Wi!
echo !n!

些语句前,它们里面的变量n不会马上被CMD替换(启用延迟后,CMD变得有耐性啦^_^),而未被替换的话,那么n就还是变量,而不是常量。等到执行
set n=!n:ld.=t!等这几句时,变量n才被替换。这样每个set命令都能感知变量n的任何变化,从而作出正确的替换行为。这就是变量延迟啦!

可跳过:

什么,说我讲得不好?没办法啊,因为偶太菜啊,只知道这些。偶只是淘两顿饭吃而已,望大家谅解啊,不要再拿砖头砸偶。。。不然偶就~~~~~~~~~~叫救命!^_^

这是正文不可跳过:

不要以为只有for才要用变量延迟,下面这个例子同样需要
例3:这是个错误的例子
CODE: [Copy to clipboard]



@echo off
set mm=girl&echo %mm%
pause
执行后依然显示“ECHO 处于关闭状态”。

因是没有启用延迟,而且在set mm=girl&echo %mm%语句前没有其它命令对mm进行赋值。这时当CMD执行set
mm=girl&echo
%mm%语句前,就已经急不切待地把变量mm的值替换了,而又因为前面没给mm赋值,所以mm被替换为空值,变成常量。等到echo命令执行时,它其实是
echo一个不会变化的常量,本例中即是空值。

有人会问,echo前面不是给mm赋值了吗?
这个就要关系到CMD解释命令的步骤,大家可以参详本帖开头willsort的帖子。

的来说是,如果不启用变量延迟,在本例中,echo是不会理会也不会知道,它前面(指同一行语句)是否有其它命令给mm赋值。它只会从set
mm=girl&echo
%mm%这句以上的语句中获取它所要显示的变量的内容,也就是说,上一行或上几行的命令将mm设置成什么值,echo命令就显示什么值。
大家这样做就明白了:
CODE: [Copy to clipboard]



@echo off
set mm=boy
set mm=girl&echo %mm%
pause
看看显示什么结果就知道了!

这样编写例3才正确:
CODE: [Copy to clipboard]



@echo off&setlocal EnableDelayedExpansion
set mm=girl&echo !mm!
pause
开启了变量延迟,变量扩展(替换)的行为就推迟到echo命令执行时,这时echo能感知它前面的命令(本例的set)对变量mm做了什么“坏事”,从而作出正确的判断并执行




没有评论:

发表评论