⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 参数问题一点谈.txt

📁 DOS和批处理技术 这些是我长期学习积累下来的总共有47个文件
💻 TXT
字号:
最近编写了一个批处理程序,想让程序能够灵活的接收两个以下的参数,但在完成过程中几经卡壳,比如怎么解决数量不等的参数个数,怎么实现参数类型的判断。经过一段时间的思考和摸索,总算比较满意的解决了这些问题。接下来我谈谈这个过程,如果你想测试效果的话请在 NT 系统下进行。
    先交待一下这个批处理程序想要接收的参数,一个参数为路径,另一个参数为数字。这样便有了下面的几种组合变换:
1、空
2、路径
3、数字
4、路径 + 数字
5、数字 + 路径
6、路径 + 路径
7、数字 + 数字
前五种情况是程序需要处理的正常的参数组合,后两种是不期望的组合。先看下面一段演示程序,一起来探讨这个过程的处理与实现。

--------------------------------------------------------------------------------


1│@echo off
2│setlocal
3│set "p1=%~1"
4│set "p2=%~2"
5│set flag_d=0
6│set flag_n=0
7│if not defined p2 (
8│        if not defined p1 (
9│                set "directory=."
10│                ) else (
11│                        set "directory=."
12│                        call :_test "%p1%"
13│                        )
14│) else (
15│        call :_test "%p1%"
16│        call :_test "%p2%"
17│                )
18│if %flag_n% == 2 echo 参数为两个数字 &goto :EOF
19│if %flag_d% == 2 echo 参数为两个目录 &goto :EOF
20│echo 目录为:%directory%        数字为:%number%
21│goto :EOF
22│
23│:_test
24│set "x=%~1"
25│set /a "y=x+1-1"
26│if "%y%" == "%x%" (
27│        set "number=%x%"
28│        set /a flag_n+=1
29│        ) else (
30│                pushd "%x%" 2>nul
31│                if errorlevel 1 set "directory=." &goto :EOF
32│                set "directory=%x%"
33│                set /a flag_d+=1
34│                popd
35│                        )
36│goto :EOF
在前六行中,flag_n 与 flag_d 分别是记录参数中数字和目录个数的两个变量并在以后使用,其余不作过多解释。重点看看第7行到第17行,这是一个 if...else... 分支结构,第一个分支又被分割成为了两部分,p1,p2两个变量分别记录了 demo.cmd 所接收的参数1和参数2,所以整个部分被分成了可以用参数个数描述的,即无参数,一个参数,和两个参数三种情况。分别看看每种分支情况都执行了什么操作。

    先说第9行也就是无参数的情况,语句含义为将变量 directory 赋值为“.”,有必要细说一下这条语句,既然没有任何参数输入到 demo.cmd 为什么还要设置变量 directory 呢?这样做的目的是给 directory 变量设置一个默认值,在以后的调用中如:dir %directory% ;for /r "%directory%" in (*.*) do ....这样类似的命令中即使 demo.cmd 没有接收到路径参数也不会出错,因为有这个默认的“.”,也就是使其在缺省状态下代表当前目录。当然是否确实有必要这样做要看你以后的命令如何使用 directory 这个变量。由于上面的代码只是一个参数接收的演示,也就没有后续的相关操作。如果你不需要对 directory 防空设计,可以将第8-10行替换为 “if defined p1 (” 将其简化,而只保留下一个分支。

    下面谈谈上段提到的下一个分支,也就是第二个 if 语句的 else 部分,即一个参数的情况。因为这一个参数的内容仍然会是路径、数字其中之一,所以还需将变量 directory 赋值为“.”,以防碰到的参数是数字,也就是第11行的功能。再看看第12行,以 p1 为参数跳转到标签 _test ,完成一次类似功能函数的调用。我们不知道完成了什么功能,先放放一放,往下看。下面到了第一个 if 语句的 else 部分,即两个参数的情况。发现分别以 p1 p2 调用了两次 _test 函数。这回我们有必要研究一下 _test 函数到底完成了什么功能。

    直接跳转到第23行,看语句首先将上面调用时发送的参数赋值给变量 x ,接下来执行一次算术操作将值赋给变量 y ,先加一再减一,有些不知所以。再往下看看 if 语句的第一个分支,如果 x 与 y 的值相等,将 x 值赋给变量 number ,并且将 flag_n 加一,我们还记得上文提及 flag_n 是记录参数中数字个数的变量,看来 x 与 y 的值相等,就断定 x 也就是上面调用时传送的参数是一个数字。为什么会这样?第25行应该是关键,在这里有一个小技巧,先插一段 set 帮助:
“在表达式中的任何非数字字符串键作为环境变量名称,这些环境变量名称的值已在使用前转换成数字。如果指定了一个环境变量名称,但未在当前环境中定义,那么值将被定为零。这使您可以使用环境变量值做计算而不用键入那些 % 符号来得到它们的值。”
    现在清楚 set /a "y=x+1-1" 这一句的执行过程了吧! x 被替换为它自身变量值参与运算,当 x 值为数字时先加一再减一其值不变也就是 y=x ;当 x 值为非数字时其值将被定为零,先加一再减一后即 y=0 。所以据此也就可以判断 x 值是否为数字了。细心人会猜想要是 x 本身等于 0 怎么办,这是特殊情况可以在 set /a 句前加以判断,改变程序执行顺序完成指定操作。但是我们这种将变量直接参与数值运算的处理方法也有局限性,比如 x 值 为 0123 会被判断为非数字,这是因为以 0 开头的数字会被解释为 8 进制数字其值为 83 。所以我们可以正确判断的只是自然数字,有方法能回避或者解决吗?我们待会再谈这个问题。

    接下来我们再来看 _test 函数 if 语句的 else 分支,第30行 pushd "%x%" 会保存当前目录,供后续命令 popd 命令使用,并切换到 x 值所表示的目录,简单说就是保存当前目录,并更改目录。下一行根据 pushd 命令的执行情况决定程序的转向,错误的话也就是非目录情况仍然设置 directory 为“.”并退出函数。第32-34行很简单 pushd 执行成功将 directory 设为 x 的值, flag_d 值增一,然后切换到被保存起来的目录。这样便完成了是否是目录的判断。看一下我们发现忽略了非数字非目录的错误输入情况,这只是为了更好的理解这个过程而做的忽略,你可以在开头部分设置一个 flag_o 变量,并在 if errorlevel 1 句增加 set /a flag_o+=1 来记录这种情况。当然为了便于理解和描述我用了并行执行多个命令的连接符“&”;实际中你可以用括号括起多条语句段来分别执行。

    这样我们便实现了数字、目录和其他字符的判断,再回到主程序就好理解了,只是将我们保存的信息显示出来,实际应用中的话再供其他命令使用。想想我们还有什么遗漏情形,比如一个参数 456 是一个目录怎么办,我们可以在第27行前加一个是否为目录的判断?而存在 456 这个目录但本身是我们想要的一个数字怎么办?这是一个没法回答的问题,所以避免这样种种岐义情况最好的办法是要求输入全路径也就是文章开头提到的这个词,而不是我们文章中部一直在使用的目录这个词。我们再来谈谈以零开头的数字的问题,既然要求的是全路径,零开头肯定不是目录,我们用取子字符串命令循环替换掉前面的零再做判断。事实上我们有必要这样做吗?我不敢说没有,那要看你对程序的容错要求程度了。

    回过头来再看看这种参数的处理方式,会发现很难应对多参数的复杂情况,更好的方式应该是 demo /A... /B... /C...这样的接收处理模式,用选项来限定参数。这样的好处是只要按限定符接收就行了,而不用将无顺序的参数交给批处理程序分析判断。这只是初步想法还不知是否能转成可行实用的批处理程序,欢迎朋友们一起来探讨。


本文来自:DOS资源站(www.cmdos.net) 详细出处参考:http://www.cmdos.net/article/sort03/info-28.html

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -