中国DOS联盟论坛

China DOS Union

-- Unite DOS · Advance DOS · Grow DOS --
Union site: www.cn-dos.net Forum site: www.cn-dos.net/forum
Guest | Log in | Register | Members | Search | China DOS Union
中国DOS联盟论坛
The time now is 2026-08-08 15:26
47,811 topics / 349,895 posts / today 0 new / 48,253 members
DOS批处理 & 脚本技术(批处理室) » [Original] A Little Discussion on Batch Processing Parameter Issues
Printable Version  18,835 / 32
Floor1 无奈何 Posted 2005-11-17 16:42
荣誉版主 Posts 356 Credits 1,338
### A Little Discussion on Batch Processing Parameter Issues
Recently, I wrote a batch processing program and wanted the program to flexibly receive up to two parameters. However, I encountered difficulties during the process, such as how to handle different numbers of parameters and how to realize the judgment of parameter types. After some time of thinking and exploration, I finally solved these problems satisfactorily. Next, I will talk about this process. If you want to test the effect, please do it under the NT system.

First, let's explain the parameters that this batch processing program is supposed to receive. One parameter is a path, and the other is a number. Then there are the following several combination transformations:
1. Empty
2. Path
3. Number
4. Path + Number
5. Number + Path
6. Path + Path
7. Number + Number
The first five cases are the normal parameter combinations that the program needs to handle, and the latter two are the unexpected combinations. Let's first look at the following demo program and discuss the processing and implementation of this process together.


In the first six lines, flag_n and flag_d are two variables to record the number of numbers and directories in the parameters respectively and will be used later, and the rest will not be explained too much. Focus on lines 7 to 17. This is an if...else... branch structure. The first branch is further divided into two parts. The two variables p1 and p2 respectively record the parameter 1 and parameter 2 received by demo.cmd, so the entire part is divided into three situations that can be described by the number of parameters, namely no parameters, one parameter, and two parameters. Let's see what operations are performed in each branch situation respectively.

First, let's talk about the situation of no parameters in line 9. The statement means assigning the variable directory the value ".". It is necessary to explain this statement in detail. Since no parameters are input to demo.cmd, why set the variable directory? The purpose of this is to set a default value for the directory variable. In subsequent calls, such as dir %directory%; for /r "%directory%" in (*.*) do .... In such commands, even if demo.cmd does not receive the path parameter, there will be no error because there is this default ".", that is, it represents the current directory in the default state. Of course, whether it is necessary to do this in this way depends on how you use the directory variable in subsequent commands. Since the above code is just a demonstration of parameter reception, there are no subsequent related operations. If you don't need to design the directory to be empty, you can replace lines 8-10 with "if defined p1 (" to simplify it and only keep the next branch.

Next, let's talk about the next branch mentioned above, that is, the else part of the second if statement, that is, the situation of one parameter. Because the content of this one parameter will still be either a path or a number, it is necessary to assign the variable directory the value ".", just in case the parameter encountered is a number, that is, the function of line 11. Then look at line 12, which jumps to the label _test with p1 as the parameter to complete a call similar to a function. We don't know what function is completed, so let's put it aside and look down. Then comes the else part of the first if statement, that is, the situation of two parameters. It is found that the _test function is called twice with p1 and p2 respectively. Now we need to study what function the _test function actually completes.

Directly jump to line 23. First, the statement assigns the parameter sent above to the variable x. Then, an arithmetic operation is performed to assign the value to the variable y, adding 1 first and then subtracting 1, which is a bit confusing. Then, look at the first branch of the if statement. If the values of x and y are equal, assign the value of x to the variable number and add 1 to flag_n. We still remember that flag_n is the variable to record the number of numbers in the parameters. It seems that if the values of x and y are equal, it is determined that x, that is, the parameter sent above, is a number. Why is this? Line 25 should be the key. Here is a small trick. First, insert a set help:
"In any non-numeric string in the expression is treated as an environment variable name, and the value of these environment variable names is converted to a number before use. If an environment variable name is specified but not defined in the current environment, then the value will be set to zero. This allows you to use environment variable values for calculations without having to type those % symbols to get their values."
Now it is clear the execution process of the sentence set /a "y=x+1-1". The x is replaced by its own variable value to participate in the operation. When the x value is a number, adding 1 first and then subtracting 1 leaves its value unchanged, that is, y = x; when the x value is a non-number, its value will be set to zero, and after adding 1 first and then subtracting 1, y = 0. So based on this, it can also be judged whether the x value is a number. A careful person will guess what if x itself is 0. This is a special case. You can judge before the set /a sentence and change the program execution order to complete the specified operation. However, this processing method of directly participating the variable in numerical operation also has limitations. For example, the x value 0123 will be judged as a non-number, because the number starting with 0 will be interpreted as an octal number with a value of 83. So the natural numbers that we can correctly judge are only natural numbers. Is there a way to avoid or solve this problem? We will talk about this problem later.

Next, let's look at the else branch of the if statement in the _test function. Line 30 pushd "%x%" will save the current directory for subsequent commands to use the popd command, and switch to the directory represented by x. Simply put, it saves the current directory and changes the directory. The next line decides the program's turn according to the execution situation of the pushd command. If it is wrong, that is, the non-directory situation, it still sets directory to "." and exits the function. Lines 32-34 are very simple. If pushd is executed successfully, set directory to the value of x, increment flag_d by 1, and then switch to the saved directory. In this way, the judgment of whether it is a directory is completed. Let's see that we have ignored the error input situation of non-number and non-directory. This is just to better understand this process and is ignored. You can set a flag_o variable at the beginning and add set /a flag_o+=1 in the if errorlevel 1 sentence to record this situation. Of course, for the convenience of understanding and description, I used the connection符 "&" for executing multiple commands in parallel; actually, you can use parentheses to enclose multiple statement segments to execute them respectively.

In this way, we have realized the judgment of numbers, directories and other characters. Then it is easy to understand when returning to the main program, just display the information we saved, and in practical applications, it will be used for other commands. Think about what omissions we have. For example, what if one parameter 456 is a directory? We can add a judgment of whether it is a directory before line 27? And what if there is a directory 456 but it is a number we want? This is an unanswerable question. So the best way to avoid such ambiguous situations is to require entering the full path, which is the word mentioned at the beginning of the article, instead of the word directory we have been using in the middle of the article. Let's talk about the problem of numbers starting with zero. Since the required is the full path, numbers starting with zero must not be directories. We can use the substring extraction command to loop and replace the preceding zeros and then make a judgment. In fact, is it necessary for us to do this? I can't say no, that depends on the degree of fault tolerance you require for the program.

Looking back at this way of parameter processing, we will find that it is difficult to cope with the complex situation of multiple parameters. A better way should be the receiving and processing mode like demo /A... /B... /C..., using options to limit the parameters. The advantage of this is that you just need to receive according to the qualifier, instead of leaving the unordered parameters to the batch processing program for analysis and judgment. This is just an initial idea and I don't know whether it can be converted into a feasible and practical batch processing program. Friends are welcome to discuss together.

Postscript: Originally, I just wanted to record the problems I encountered here, but I didn't expect to be so wordy. If there are any omissions, I hope to be corrected.
Floor2 willsort Posted 2005-11-17 18:31
元老会员 Posts 1,512 Credits 4,432
Re 无奈何:

A very insightful topic. Based on its content and depth, I believe it can be categorized into the (Development Room), but there are too few people who can appreciate it there, so let's temporarily discuss it here.

Regarding the support for dynamic parameters, I came into contact with it at the beginning of learning batch processing, but I didn't go deep at that time, so omissions were inevitable. Later, when I was writing the command-line enhanced version (VisitCE) of that text traversal program, I tried to explore it more deeply, but once I got into it, it was like a maze of ghosts, complicated, with too many things to consider and deliberate. At this time, I had a deeper understanding of the flexibility of the DOS command line.

Regarding the support for multiple dynamic parameters, I suggest using :loop and goto loop loops to analyze parameters, which can somewhat avoid the program falling into the maze of if else, which is also the usual practice for code handling parameters in other high-level languages. Treat all parameters equally, first judge whether it is empty, then judge its category, then judge whether it is valid, and finally judge whether it can be saved (that is, whether it has been saved or other situations). In this way, even if processing any number of dynamic parameters, there is no need to change the code too much.

In addition, the classification method of dividing parameters into directories and numbers will inevitably lead to the ambiguity problem of parameters, thus complicating the program analysis. Many high-level languages stipulate that variable names are not allowed to start with numbers, which is based on this reason (the counterexample is the environment variables of DOS). To avoid it, it is necessary to re-divide the categories of parameters. The full path you mentioned is a compromise.

For judging whether a parameter is a number, if external commands are allowed, you can consider the regular expression filtering of finstr.

Finally, give a question for everyone to discuss: How to achieve the same requirement under MS-DOS?
Floor3 无奈何 Posted 2005-11-25 23:42
荣誉版主 Posts 356 Credits 1,338
There are few who agree, just as I guessed, this is indeed a low - activity post. I originally wanted to continue with a next part to finish the discussion of this issue, and also to serve as a summary of more than half a year's study of batch processing, but I really don't have the energy or the heart to complete it.

Thanks to Brother willsort for the affirmation and encouragement, your suggestions have benefited me a lot.

There was a loose end in the previous article, which really makes me unhappy, but I have no heart to continue. I will post another section of batch processing program, as the handling of the remaining problem in the previous article. This is a section of my certain program, after partial changes, it is made into a demonstration program. This code is the result of my several supplements and modifications, which may be a bit messy, and I won't explain it, because friends who are interested in this should be able to understand it all.




[ Last edited by 无奈何 on 2005-11-27 at 15:02 ]
Floor4 willsort Posted 2005-11-26 19:32
元老会员 Posts 1,512 Credits 4,432
Re 无奈何:

Seeking a kindred spirit is hard, an old adage. Brother's emotional response shows you're a man of sentiment.

The following is my code, mainly for MSDOS/Win9x environments, and it should be mostly fine for NT's too, though not strictly tested, so I can't guarantee it.

There's no validation of parameter validity in the code, and no verification for encountering duplicate switches. But in practical applications, you can relatively easily insert validation code into the relevant modules according to the actual situation of various types of parameters.

Brother's code has the following questions:

1. set "_temp=%~1", I guess the purpose of saving the parameter to a variable is to remove the double quotes in the parameter, which is the function of %~1, but I don't understand why both the variable name and the parameter are enclosed in quotes.

2. Variables m and n, I guess their role is to mark the parity of parameters, that is, to indicate whether the parameter is a switch or a variable value, but can it be marked with the true/false of a single variable? In my scheme, because I use double shift to avoid the selection of switches and variable values, this may cause problems in identifying prog /i /o, but if validity verification is added in SwitchI, it can also be avoided.

3. set /a I=1,F=0,V=0,L=0,O=0,n=1, how will this setting recognize prog /i input /o output /i input2?



[ Last edited by willsort on 2005-11-26 at 19:35 ]
Floor5 无奈何 Posted 2005-11-26 23:35
荣誉版主 Posts 356 Credits 1,338
to: willsort

Seeking a bosom friend like the legend of "High Mountains and Flowing Water", I am extremely delighted to receive your reply.

1. As you said, "%~1" is indeed to remove the double quotes. If a variable's value may or may not have double quotes, it will cause some inconvenience in calling. When a variable "ABC" contains characters like spaces and semicolons and you call a label function, "call :test %ABC%" will definitely split ABC into multiple parameters, so "call :test "%ABC%"" is used, which will cause the passed parameter to be surrounded by double quotes and sometimes by two pairs of double quotes. I also encountered some other problems in my application, but I can't remember them for the moment. So I also developed the habit of uniformly removing double quotes.

There are also several advantages to enclosing the variable name and value with double quotes. First, in this way, you can use a variable name with spaces, such as "set "A B=A-B"". Second, when assigning a variable, it prevents accidental spaces at the end, such as "set "A="". These small tricks can avoid some unnecessary troubles.

2. The roles of variables m and n are to mark whether they are parameter markers (switches) and parameter variables, but not judged by parity. I initially also used a variable to judge by remainder according to parity, and the situation where all subsequent parts were completely wrong occurred when two valid parameter markers appeared continuously. The role of n is to determine that a non-valid parameter marker immediately following a valid parameter marker is a parameter variable. The role of m is just the opposite; it will recognize that a parameter variable is immediately followed by a parameter marker.

3. The role of setting the flag variables I, F, V, L, O is to make the program correctly receive parameters that are out of order and of an indefinite number. When a valid parameter marker arrives, the corresponding flag variable is set to 1, and other flag variables are set to 0; entering the next loop, when a valid parameter variable arrives, according to whether the flag variable is 1, you can judge which parameter marker was received last time, and then set the corresponding variable value. When there are two repeated parameters as you mentioned, the value of the latter will replace the value of the previous one, that is, the last input prevails. Also, when you want a flag variable to only act as a switch without a parameter variable, you can directly add an assignment statement at the initial judgment to solve this problem.

I have carefully read your example. The code is indeed excellent, and the fluency far exceeds my crude work. If there is one more layer of judgment to perfect the two branches of single-step and double-step, it can also well solve the situation where the flag variable only acts as a switch.

[ Last edited by 无奈何 on 2005-11-27 at 13:08 ]
Floor6 willsort Posted 2005-11-29 17:34
元老会员 Posts 1,512 Credits 4,432
Re 无奈何:

I'm very sorry! Due to various subjective and objective reasons, my reply was forced to be delayed.

1. Brother's explanation of "set "_temp=%~1" is indeed reasonable, especially the prompt to prevent trailing spaces; because I have been writing batch code under MSDOS/Win9x for a long time, and I don't have many opportunities to contact parameters with spaces or quotes, so I didn't consider it comprehensively.

After testing, it is found that ntcmd.set handles the quotation marks in the command line very comprehensively, and can properly handle cases like set _temp=This is "test string" ! or set "_temp=This is "test string" !"; but many problems will occur under MSDOS/Win9x. Also, whether under MSDOS/9X_COMMAND or XP_CMD, the usage of set var name=value is valid.

2. I have basically understood the role of m n. It is indeed necessary for the two variables to mark the switch items and non-switch items respectively.

3. At first, I thought that your setting would allow repeated setting of switches, and this is usually an incorrect usage, and the 6/7 combination you mentioned in the main post is also considered "unexpected" by you. But later I thought that such usage might be needed in some occasions, which I have seen in command lines similar to unix and some complex batch processing, so I just accepted its existence.

4. Regarding my code, when I originally designed this program, I listed both prog /i /o output and prog /i input /i input2 as wrong parameter usages. Now it occurs to me that the situation of prog /i /o output is still very common, especially when some parameters are just switches to turn on or off certain functional features, so I made simple improvements according to the single-step and two-step classification you mentioned.

In addition, my program also allows the situation of prog /i input1 /i input2, but opposite to your code, it only takes the first set value; as you said, it is very simple to change it to take the last one, just delete the if condition for judging whether it has been set; and if you want to prohibit this situation, you just need to reverse the condition and perform error handling. But it is more troublesome to handle switches that may not contain set values, and you need to check the parameters. The following is the new code, completed online, not tested!



[ Last edited by willsort on 2005-11-30 at 12:24 ]
Floor7 无奈何 Posted 2005-11-29 21:21
荣誉版主 Posts 356 Credits 1,338
to: willsort

In fact, in the case of prog /i input1 /i input2, both taking the former and the latter are reasonable, just a matter of strategy, and you can completely do whatever is convenient.

Brother's following code seems to have missed a possible situation according to your function prompt.

:SwitchV
for %%s in (l L i I o O f F v V) do if "%2"=="/%%s" set filter_v=default
for %%s in (l L i I o O f F v V) do if "%2"=="/%%s" goto NextArg
set filter_v=%2
goto Next2Arg

Test: prog /i input1 /v was found not to be assigned as envisioned. You can add a statement as follows:


There is also a question, why didn't brother merge the statements with the same conditions. Such as:

This can reduce one loop, or more concisely merge the if statements. Is it a consideration of compatibility? I don't understand the problems under DOS.
Floor8 willsort Posted 2005-11-29 22:19
元老会员 Posts 1,512 Credits 4,432
Re 无奈何:

1. The issue with prog /i input1 /v is indeed a problem, and your modification is necessary; when actually applying it, it is also necessary to prevent situations like /x /y or other invalid switches, and at this time, validity verification is essential.

2. The two identical for + if statements are indeed due to compatibility considerations. In MSDOS / Windows, statement blocks are not supported. Although the two statements can be combined through special methods, it is not adopted here. On one hand, it is for compatibility considerations, and on the other hand, it is for readability considerations.

3. In the case of prog /i input1 /i input2, taking the former and the latter is suitable for different application scenarios.

For example, in some scenarios, we may use a variable to save a command line with parameters, and then refer to it in a certain subsequent environment. At this time, we may need to change a certain switch or parameter, but for some reason, we cannot modify the variable. At this time, we need to adopt the strategy of taking the latter, so that we can add new switches or parameters after referring to the variable to change the running state of the program.

As for the strategy of taking the former, it is more common, but generally has no special purpose. But there is a special case opposite to the above. We may use a variable to save part of the parameters of the command line, and then refer to it in a certain subsequent environment. At this time, we may need to fix a certain switch or parameter, but for some reason, we cannot modify the variable. At this time, we need to adopt the strategy of taking the former. Or some programs may pre-set some common command line usages in various forms, and do not want users to intentionally or unintentionally modify these usages, then the strategy of taking the former is also needed. This is similar to the -- command line termination parameter in some unix-like programs.

In addition, I just noticed your new signature, which is indeed creative and skillful, but the wording seems a bit sentimental, and I am afraid it may bring a negative impact on the new users of the forum. Just a joke

[ Last edited by willsort on 2005-11-29 at 22:26 ]
Floor9 无奈何 Posted 2005-11-30 00:19
荣誉版主 Posts 356 Credits 1,338
Haha, I'll use your framework from now on. Give me a license!

My signature really took some effort. I tried to be as concise as possible, wanting it to have the least number of characters while maintaining functionality. This is the best I can do right now (replacing %ComSpec% with cmd doesn't count). Of course, it lacks readability and is made a bit mysterious. Moreover, helplessness is not a lasting attitude towards life nor a reflection of the current situation. It can be understood as a self - mocking and comforting for various things that can't be done or shouldn't be done, whether it's about oneself or others. Do more self - comfort and adjustment and less idle complaining. It is also reflected a lot in oneself and in others. Sadness is definitely there, and it's also low - key, but what is hoped for is not depression. My original words were "Eventually, it's helpless", but I found it wasn't my original intention, so I quietly changed one word.
Floor10 willsort Posted 2005-11-30 10:35
元老会员 Posts 1,512 Credits 4,432
Re 无奈何:

My code neither declares Copyright nor attaches any License, so there is no issue of authorization. Of course, you can use it freely. I appreciate the spirit of free sharing on the network.

However, a good framework or code needs to be formally applied only after repeated testing and continuous improvement. And my code is just a piece of code written online, which may have many potential problems and imperfections.

Before falling asleep last night, I suddenly woke up to a place that can be improved again, that is, the double for statement you mentioned. I omitted the previous for. The code is not reposted, just the original V2 version code on floor 6 is edited.
Floor11 maya0su Posted 2006-01-16 23:43
中级用户 Posts 131 Credits 241
Those who suffer discipline themselves, those who act are helpless...
Life is inherently a painful thing, but since we are born as human beings, we cannot sink, we can only振作up, my beloved ones... But alas, flowers wither...
I carefully read Brother Wunaihe's post repeatedly. In the end, I won't participate in the discussion because I just discovered this post today... And my ability is very limited, and I can only study further for the questions you raised... And Brother Willsort's reply is really wonderful, you completed the initial设想between asking and answering, congratulations! I can only be happy for you!
The original vision of the Internet was freedom and sharing, but now the Internet has become a tool for people to make money, which really makes us old folks feel cold. Based on the spirit of freedom and sharing, I sincerely hope to use our meager efforts to continue this kind of sharing and freedom. Brother Wunaihe's signature I tested, it's very interesting!
Try to come up with a question: Can you write a batch processing program to display a passage in a way of displaying one character at a time? And it's a batch file, double-click to display this short passage in the window, and pause the screen after completion!
Just want to play a game with brothers, whether you pay attention or not doesn't matter... Just to make you smile!
Floor12 mrhjzhang Posted 2006-01-19 16:45
初级用户 Posts 39 Credits 100
Passing by, just showing support
Floor13 220110 Posted 2006-02-02 10:26
荣誉版主 Posts 313 Credits 718
Try to come up with a question: Can you write a batch program that displays a passage one character at a time? And it's a batch file, which, when double-clicked, displays this passage in the window and pauses the screen when done!


Re maya0su:
Refer to the personal signature of Wunaaihe.
But its code is really confusing. Hehe
Hope friend Wunaaihe can organize it into a more readable format.

[ Last edited by 220110 on 2006-2-4 at 16:54 ]
Floor14 zah98 Posted 2006-10-22 11:40
新手上路 Posts 4 Credits 9
Support it's a bit hard to understand
Floor15 gxfc Posted 2006-10-22 13:27
新手上路 Posts 11 Credits 17
Good post, worthy of study
1 2 3  Next
[ Contact the Union admin team - 中国DOS联盟 - Standard version ]
Sponsored by ifanr Inc | © 2001–2023