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
### 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
Recent Ratings for This Post
( 10 in total)
Click for details
| Rater | Score | Time |
|---|---|---|
| 雨露 | +20 | 2007-01-09 09:24 |
| x412637729 | +1 | 2007-02-16 03:46 |
| axi | +2 | 2007-03-17 18:51 |
| caucfeiyu | +2 | 2007-04-14 10:58 |
| tongwandou | +1 | 2007-04-22 05:52 |
| mirking | +1 | 2007-09-03 20:33 |
| 313885174 | +2 | 2008-01-18 10:01 |
| — | +1 | 2008-03-30 10:30 |
| For | +1 | 2009-05-28 10:16 |
| amao | +4 | 2010-04-02 02:32 |

