Windows 批处理脚本指南: 变量

今天我们将介绍变量,这些变量在复杂点的批处理程序中都是必需的。变量的语法可能有点奇怪。:smile_cat:

Variable Declaration


DOS不需要声明变量。未声明/未初始化变量的值是空字符串或""。大多数人喜欢这样,因为它减少了需要编写的代码量。就我个人而言,我喜欢在使用变量之前声明一个变量,因为它可以捕获了一些简单的错误,比如变量名拼写错误。

Variable Assignment


使用 SET 命令为一个变量赋值。

SET foo=bar

注意:不要在名称和值之间使用空格;SET foo = bar 将不起作用,但 SET foo=bar 就可以。

/A 开关支持算数操作。这是一个有用的工具,如果您需要验证该用户输入是一个数值。

SET /A four=2+2
4

一般的惯例,变量经常使用小写名称,系统变量(环境变量)一般是大写。这些环境描述了在您的系统中哪里可以找到某些东西,例如 %TEMP%,它是临时文件的路径。DOS是不区分大小写的,所以这个惯例并不是强制的,但是让脚本更容易阅读或者故障排除,倒是个好主意。

警告:SET终覆盖任何现有变量。在编写脚本时,先验证下是否覆盖了系统范围的变量。ECHO %foo%可以快速确认 foo 是不是一个现有的变量。例如,很容易将一个变量命名为 “temp”,但这将会改变广泛使用的 “%temp%” 环境变量的含义。DOS包含一些“动态”的环境变量,它们的行为更像是命令。这些动态变量包括 %DATE%%RANDOM%%CD%。最好不要覆盖这些动态变量。

Reading the Value of a Variable


在大多数情况下,可以通过%运算符将变量名括起来读取变量值。下面的示例将变量 foo 的当前值打印到控制台输出。

C:\> SET foo=bar
C:\> ECHO %foo%
bar

在一些特殊的情况下,变量不使用 % 这种语法,我们将在本系列后面讨论这些特殊情况。

Listing Existing Variables


SET 命令不加参数,会输出所有的变量到控制台。这些变量大多数是环境变量,比如 %PATH% 或者 %TEMP%

无参数的SET命令

注意:调用SET将列出当前会话的所有常规(静态)变量。不包括动态环境变量,如 %DATE%%CD%。在SET帮助文本的末尾列出这些动态变量,可以通过调用 SET /? 来查看。

%CD% - 扩展到当前目录字符串。
%DATE% - 用跟 DATE 命令同样的格式扩展到当前日期。
%TIME% - 用跟 TIME 命令同样的格式扩展到当前时间。
%RANDOM% - 扩展到 0 和 32767 之间的任意十进制数字。
%ERRORLEVEL% - 扩展到当前 ERRORLEVEL 数值。
%CMDEXTVERSION% - 扩展到当前命令处理器扩展版本号。
%CMDCMDLINE% - 扩展到调用命令处理器的原始命令行。
%HIGHESTNUMANODENUMBER% - 扩展到此计算机上的最高 NUMA 节点号。

Variable Scope (Global vs Local)


默认情况下,变量对整个命令提示符会话是全局的。调用SETLOCAL命令,将变量变为局部变量。任何局部变量赋值在调用ENDLOCALEXIT,或者当执行到达脚本中的文件结尾(EOF)时都会恢复。

本示例演示如何在名为HelloWorld.cmd的脚本中更改名为foo的现有变量。 当脚本退出时,%foo%会恢复的原始值。

HelloWrold.cmd

SETLOCAL
SET v=Local Value
ECHO %v%
变量恢复

一个真实的例子应该是修改系统的%PATH%环境变量。

PATH: 存储了执行命令时搜索的目录列表。

修改系统Path环境变量

Special Variables


有些特殊情况,变量的使用有些小差异。在命令行中给脚本传递的参数也是变量,但是不要使用%var%语法。 而是用%跟一个0-9的数字读取每个参数,数字代表参数的位置。 在稍后的创建函数的例子中,将会看到同样的风格。

还有一个使用!的变量语法,就像!var! 这是一种称为延迟扩展的特殊情况。 当我们讨论条件(if / then)和循环时,将会讲解更多关于延迟扩展的内容。

Command Line Arguments to Your Script


你可以使用特殊的语法读取传递给脚本的命令行参数。 语法是一个单一的%字符,后面是从0到9的参数的序号位置。零序参数是批处理文件本身的名称。 所以我们脚本HelloWorld.cmd中的变量%0将是“HelloWorld.cmd”。

命令行的第一个非空参数就是 %1, 第二个就是%2 ……, 第九个就是%9

Note: DOS确实支持9个以上的命令行参数,然而,你不能直接读取第9个之后参数。这是因为特殊变量语法不能识别%10或更高。 实际上%10,它只识别到%1, 0 作为一个字符被拼接到后边。

通过一个例子来测试下,写几个脚本命名为 arguments.cmd, 内容如下

echo %1
echo %10

不能识别%10

从运行结果来看,%10实际上是: 第一个参数 + 0

使用SHIFT命令从参数列表中弹出第一个参数,这使得所有的参数都向左移动,这样第十个参数就可以通过%9来获取了。在循环的部分,将会详细讲解这部分内容。

Tricks with Command Line Arguments


命令行参数还支持一些非常有用的可选语法,针对文件路径参数,可以解析作为命令行参数的文件的路径、时间戳或大小。这个超级有用的特性文档有点难找 :pouting_cat:,运行 for /?,在页面的最末尾。

  • %~I从第I个命令行参数中删除引号,在处理文件路径参数时非常有用。之前讲过,带空格的路径需要用引号括起来,但是多次括起来就会导致错误。这里的I可以事0~9的整数。

  • %~fI 展开完整路径
    例如 args.cmd

    echo %~f1
    

    调用

    args.cmd .\adoble
    

    输出:C:\Users\Edward\Desktop\Adobe

  • %~fsI 与上边的类似,s 选项会生成一个 DOS 8.3[1]的短路径,例如:C:\Program Files缩写为 C:\PROGRA~1。在使用一些不处理空格的第三脚本,这个技巧很实用啊。 :wink:

  • %~dpII个文件路径参数的完整父级路径。几乎在每个批处理脚本中,我都用这个技巧来确定脚本的位置。 SET parent=%~dp0通过这个用法,可以输出脚本的所在路径。

  • %~nxII个文件路径参数的文件名(包括扩展名)。类似%0, 我也经常使用这个技巧来确定运行时脚本的名字。如果需要输出消息给用户,我喜欢在消息前面加上脚本的名字,像这样ECHO %~n0: 输出的消息,而不是直接输出ECHO 输出的消息。这样做的好处是,用户知道这个消息是从哪个脚本中输出的。如果你花了几个小时的时间为了确定错误消息是从哪个脚本输出的,是不是很崩溃?:laughing:

Some Final Polish


我总是将这些命令包含在批处理脚本的顶部:

SETLOCAL ENABLEEXTENSIONS
SET me=%~n0
SET parent=%~dp0

SETLOCAL命令能保证脚本在退出之后不覆写任何现有的变量。ENABLEEXTENSIONS[2],是SETLOCAL的一个参数,这是一个非常有用的特性,称之为启动或停用命令处理器扩展名。别问为什么真的很有用 :joy:
me变量存储了脚本的名称(不包含扩展名)。这样就能很方便的给输出的消息加上前缀ECHO %me%: 输出的消息
parent存储了脚本的所在目录,这样可以很容易的给同一目录下的其他文件拼接出完整的路径。

参考资料


  1. 8.3 filename

  2. Determines whether the extensions to the command processor (Cmd.exe)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • 个人学习批处理的初衷来源于实际工作;在某个迭代版本有个BS(安卓手游模拟器)大需求,从而在测试过程中就重复涉及到...
    Luckykailiu阅读 4,527评论 0 11
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,099评论 18 139
  • 来自陈浩的一片老文,但绝对营养。 示例工程:3 个头文件*.h,和 8 个 C 文件*.c。 初 编译过程,源文件...
    周筱鲁阅读 4,605评论 0 17
  • 记得我的生命里因体验而激发起思绪的,还真不到五次。小时候只体验了游乐场,特别是过山车的刺激,体验了比赛的激烈。但这...
    璐帆阅读 166评论 0 0
  • (碎碎念之题外话:今天接触到一套讲座,和以前写的论文内容有交叉,为充实文章论据提供了实践意义上的参考,所以准备听完...
    冥想音阅读 154评论 0 0