   『楼 主』:
最强之dos命令 – for (是新手学习FOR语句的好资料)
使用 LLM 解释/回答一下
这篇文章是网上找的,很多初学DOS的朋友对FOR语句掌握的好不是太过熟悉,希望这边文章能够给你开阔思路帮助你把FOR语句学好,主要的参数介绍和实例讲的都很清楚,也希望对DOS越来越感兴趣--->发挥你的想像力吧
正文开始
以前常觉得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 %a\CVS rd /s /q %a\CVS
先用 if exist 判断一下,是因为 for 只是机械的对每个目录进行列举,如果有些目录下面没有CVS也会被执行到。用 if exist 判断一下比较安全。
这种删除命令威力太大,请小心使用。最好是在真正执行以上的删除命令前,将 rd /s /q 换成 @echo 先列出要删出的目录,确认无误后再换回rd /s /q:
for /r . %a in (.) do @if exist %a\CVS @echo %a\CVS
可能目录中会多出一层 ".",比如 c:\proj\release\.\CVS ,但不会影响命令的执行效果。
2. 将某一文件内容或命令执行结果作为循环范围:
假如你有一个文件 todel.txt,里面是所有要删除的文件列表,现在你想将里面列出的每个文件都删掉。假设这个文件是每个文件名占一行,象这样:
c:\temp\a1.txt
c:\temp\a2.txt
c:\temp\subdir\b3.txt
c:\temp\subdir\b4.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:\mp3\Archived\05-18-01-A\游鸿明-下沙\游鸿明-01 下沙.mp3
g:\mp3\Archived\05-18-01-A\游鸿明-下沙\游鸿明-02 21个人.mp3
......
g:\mp3\Archived\05-18-01-A\王菲-寓言\王菲-阿修罗.mp3
g:\mp3\Archived\05-18-01-A\王菲-寓言\王菲-彼岸花.mp3
g:\mp3\Archived\05-18-01-A\王菲-寓言\王菲-不爱我的我不爱.mp3
......
如果我只要歌名(不要路径和".mp3"):
游鸿明-01 下沙
游鸿明-02 21个人
......
王菲-阿修罗
王菲-彼岸花
王菲-不爱我的我不爱
......
那么可以用FOR命令:
for /r g:\mp3 %a in (*.mp3) do @echo %~na
凡是 %~ 开头的操作符,都是文件名的分离操作。具体请看 for /? 帮助。
本文举的例子有些可能没有实际用处,或可用其它办法完成。仅用于体现FOR可以不借助其它工具,仅用DOS命令组合,就可完成相当灵活的任务
This article is found online. Many friends who are just starting to learn DOS are not too familiar with mastering the FOR statement. I hope this article can broaden your thinking and help you learn the FOR statement well. The main parameter introductions and examples are very clear. I also hope you will become more interested in DOS ---> Use your imagination!
### Start of the text
I used to think that the command-line function of DOS was too weak and couldn't perform very complex operations like UNIX with command lines. In fact, since MS enhanced the command line starting from WIN2K, it has borrowed quite a lot of advantages from UNIX. Although it can't be as flexible as UNIX yet, it can complete most tasks. For example, using && and space to connect two (or more) commands, and the next command is executed or not depending on the return value of the previous one, etc. Among these enhancements, the most obvious one is the FOR command.
For example, with appropriate parameters, the output of date /t can be changed from "Sat 07/13/2002" to the format you want, such as "2002-07-13":
c:\>for /f "tokens=2,3,4 delims=/ " %a in ('date /t') do @echo %c-%a-%b
2002-07-13
This example will be explained in detail in (3).
### 0. Basic application
Simply put, FOR is a loop that can generate a series of commands using the loop range you specify. The simplest example is to manually specify the loop range and then execute the specified command for each value. For example, if you want to quickly report the remaining space of each hard disk partition:
for %a in (c: d: e: f) do @dir %a\ find "bytes free"
The output will be:
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
It can be used to make some commands that don't support wildcards operate on a series of files. In WIN9X, the TYPE command (displaying file contents) doesn't support the format like *.txt (starting from WIN2K, TYPE has supported wildcards). In case of a similar situation, you can use FOR:
for %a in (*.txt) do type %a
These are not the most powerful functions of FOR. I think its most powerful functions are reflected in the following advanced applications:
1. You can use the /r parameter to traverse the entire directory tree
2. You can use the /f parameter to use the content of a text file as the loop range
3. You can use the /f parameter to use the execution result of a certain command as the loop range
4. You can use the %~ operator to separate the file name into independent parts such as file name, extension, drive letter, etc.
The examples are explained respectively as follows:
### 1. Traversing the directory tree with /r
When using file wildcards such as *.* or *.txt as the loop range of for /r, you can operate on all files (including files in subdirectories) under the current directory. For example, you want to find the word "bluebear" in the contents of all txt files (including subdirectories) in the current directory, but since find itself can't traverse subdirectories, so we use FOR:
for /r . %a in (*.txt) do @find "bluebear" %a
The @ in front of find just makes the output result not include the find command itself. This is a function that DOS has had for a long time. It has nothing to do with FOR.
When using . as the loop range, for only takes the structure (directory name) of the subdirectory as the loop range, not the files inside it. It's a bit like the TREE command, but the focus is different. The key point of TREE is to output in a very beautiful and readable format, while the output of FOR is suitable for some automatic tasks. For example, we all know that in a project managed by CVS, there will be a CVS directory under each subdirectory. Sometimes when the software is released, we want to delete all these CVS directories:
for /r . %a in (.) do @if exist %a\CVS rd /s /q %a\CVS
First, use if exist to judge, because for just mechanically list each directory, if there is no CVS under some directories, it will also be executed. Using if exist to judge is relatively safe.
This deletion command is too powerful, please use it carefully. It's best to replace rd /s /q with @echo to list the directories to be deleted first before really executing the above deletion command. Confirm that there is no problem and then replace it back with rd /s /q:
for /r . %a in (.) do @if exist %a\CVS @echo %a\CVS
There may be an extra layer of "." in the directory, such as c:\proj\release\.\CVS, but it won't affect the execution effect of the command.
### 2. Using the content of a certain file or the execution result of a command as the loop range:
Suppose you have a file todel.txt, which is a list of all files to be deleted. Now you want to delete each file listed in it. Suppose this file has each file name on one line, like this:
c:\temp\a1.txt
c:\temp\a2.txt
c:\temp\subdir\b3.txt
c:\temp\subdir\b4.txt
Then you can use FOR to complete:
for /f %a in (todel.txt) do del %a
This command can be more powerful. For example, your todel.txt is not as clean as the above example, but is directly generated by DIR, with some useless information, like this:
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 can still solve the file name in it and operate:
for /f "skip=5 tokens=5" %a in (todel.txt) do @if exist %a DEL %a
Of course, the above command is deleting. If you just want to see which files will be operated, replace DEL with echo:
for /f "skip=5 tokens=5" %a in (todel.txt) do @if exist %a echo %a
You will see:
alg0925.txt
bsample.txt
invitation.txt
skip=5 means skipping the first 5 lines (that is, the header information of DIR output), tokens=5 means taking the 5th column of each line as the loop value and putting it into %a, which is just the file name. Here I added a file existence judgment because the last line of "free" happens to be the 5th column. At present, I can't think of a good way to filter out the last two lines, so checking can be absolutely safe.
### 3. Using the /f parameter to use the execution result of a certain command as the loop range
This is a very useful function. For example, we want to know which names of the current environment variables there are (we only want the names, not the values). But the output of the SET command is in the format of "name=value". Now we can use FOR to only get the name part:
FOR /F "delims==" %i IN ('set') DO @echo %i
You will see:
ALLUSERSPROFILE
APPDATA
CLASSPATH
CommonProgramFiles
COMPUTERNAME
ComSpec
dircmd
HOMEDRIVE
......
Here, the execution result of the set command is taken as the loop range. delims== means using = as the delimiter. Since FOR /F defaults to taking the first TOKEN of each line, the variable name can be separated. If you want to list only the values:
FOR /F "delims== tokens=2" %i IN ('set') DO @echo %i
tokens=2 is the same as the previous example, which means taking the second column (separated by =) as the loop value.
Here's a more useful example:
We know that the output of date /t (/t means not to ask the user for input) is like this:
Sat 07/13/2002
Now I want to separate the date part, that is, 13:
for /f "tokens=3 delims=/ " %a in ('date /t') do @echo %a
In fact, changing tokens to 1, 2, 3, or 4 respectively will get Sat, 07, 13, and 2002. Note that there is a space after delims=/, which means / and space are both delimiters. Since this space delims must be the last item of the /f option.
Be more flexible. As mentioned at the beginning of this article, output the date in the format of 2002-07-13:
for /f "tokens=2,3,4 delims=/ " %a in ('date /t') do @echo %c-%a-%b
When there are multiple values after tokens, they will be mapped to %a, %b, %c, etc. Actually, it's related to the variables you specify. If you specify %i, they will use %i, %j, %k, etc.
Flexibly applying this point, almost nothing is impossible.
### 4. Using the %~ operator to separate the file name into independent parts such as file name, extension, drive letter, etc.
This is relatively simple, that is, the value of the loop variable is automatically separated into only the file name, only the extension, or only the drive letter, etc.
Example: To list the song names of all mp3s under c:\mp3, if you use the general dir /b/s or for /r, it will be like this:
g:\mp3\Archived\05-18-01-A\游鸿明-下沙\游鸿明-01 下沙.mp3
g:\mp3\Archived\05-18-01-A\游鸿明-下沙\游鸿明-02 21个人.mp3
......
g:\mp3\Archived\05-18-01-A\王菲-寓言\王菲-阿修罗.mp3
g:\mp3\Archived\05-18-01-A\王菲-寓言\王菲-彼岸花.mp3
g:\mp3\Archived\05-18-01-A\王菲-寓言\王菲-不爱我的我不爱.mp3
......
If I only want the song name (not the path and ".mp3"):
游鸿明-01 下沙
游鸿明-02 21个人
......
王菲-阿修罗
王菲-彼岸花
王菲-不爱我的我不爱
......
Then you can use the FOR command:
for /r g:\mp3 %a in (*.mp3) do @echo %~na
All operators starting with %~ are file name separation operations. For details, please see for /? help.
Some of the examples given in this article may not be of practical use, or can be completed by other methods. It is only used to reflect that FOR can complete quite flexible tasks without the help of other tools, only using DOS command combinations
此帖被 +35 点积分 点击查看详情 评分人:【 雨露 】 | 分数: +20 | 时间:2007-1-9 09:24 | 评分人:【 x412637729 】 | 分数: +1 | 时间:2007-2-16 03:46 | 评分人:【 axi 】 | 分数: +2 | 时间:2007-3-17 18:51 | 评分人:【 caucfeiyu 】 | 分数: +2 | 时间:2007-4-14 10:58 | 评分人:【 tongwandou 】 | 分数: +1 | 时间:2007-4-22 05:52 | 评分人:【 mirking 】 | 分数: +1 | 时间:2007-9-3 20:33 | 评分人:【 313885174 】 | 分数: +2 | 时间:2008-1-18 10:01 | 评分人:【 】 | 分数: +1 | 时间:2008-3-30 10:30 | 评分人:【 For 】 | 分数: +1 | 时间:2009-5-28 10:16 | 评分人:【 amao 】 | 分数: +4 | 时间:2010-4-2 02:32 |
|
|