The Strongest DOS Command – for (A Good Reference for Novices Learning FOR Statements)
This article is found online. Many friends who are new to 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 and more interested in DOS –→ Let your imagination run wild
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, it can already complete most tasks. For example, using && and to connect two (or more) commands, and the next one 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 with 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 content) doesn't support the format like *.txt (WIN2K starts to support wildcards for TYPE). 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 manifested 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.
Now let's explain them with examples respectively:
1. Traversing the directory tree with /r
When using wildcards like *.* 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 content of all txt files (including subdirectories) in the current directory. But since find itself can't traverse subdirectories, 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 releasing software, 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 lists each directory, and if there are no CVS in some directories, it will also be executed. It's safer to use if exist to judge.
This deletion command is too powerful, so 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 it's correct, 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 a separate 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 names in it and operate on them:
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 the DIR output), and 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. I haven't thought of a good way to filter out the last two lines for the time being, so checking it can be safe.
3. You can use 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, if you change tokens to 1, 2, 3, or 4 later, you will get Sat, 07, 13, and 2002 respectively. Note that there is a space after delims=/, which means that / and space are both delimiters. Since this space delims must be the last item in 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, almost nothing is impossible.
4. You can use 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 titles 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 title (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
凡是 %~ 开头的操作符,都是文件名的分离操作。具体请看 for /? 帮助。
Some of the examples in this article may not be of practical use or can be completed by other methods. They are 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
( 1 in total)
Click for details