返回列表 发帖

[原创] 【续】[一日一教学](44)设置变量:set

本帖最后由 Hello123World 于 2011-12-22 17:35 编辑

【原】[一日一教学]批处理系列帖子索引 http://bbs.bathome.net/thread-2576-1-1.html
【续】[一日一教学]批处理系列帖子索引 http://bbs.bathome.net/thread-13798-1-1.html


帮助信息:
显示、设置或删除 cmd.exe 环境变量。
SET [variable=[string]]
  variable  指定环境变量名。
  string    指定要指派给变量的一系列字符串。
要显示当前环境变量,键入不带参数的 SET
如果命令扩展被启用,SET 会如下改变:
可仅用一个变量激活 SET 命令,等号或值不显示所有前缀匹配
SET 命令已使用的名称的所有变量的值。例如:
    SET P
会显示所有以字母 P 打头的变量
如果在当前环境中找不到该变量名称,SET 命令将把 ERRORLEVEL
设置成 1
SET 命令不允许变量名含有等号。
SET 命令中添加了两个新命令行开关:
    SET /A expression
    SET /P variable=[promptString]
/A 命令行开关指定等号右边的字符串为被评估的数字表达式。该表达式
评估器很简单并以递减的优先权顺序支持下列操作:
    ()                  - 分组
    ! ~ -               - 一元运算符
    * / %               - 算数运算符
    + -                 - 算数运算符
    << >>               - 逻辑移位
                       - 按位“与”
    ^                   - 按位“异”
    |                   - 按位“或”
    = *= /= %= += -=    - 赋值
      &= ^= |= <<= >>=
    ,                   - 表达式分隔符
如果您使用任何逻辑或取余操作符, 您需要将表达式字符串用
引号扩起来。在表达式中的任何非数字字符串键作为环境变量
名称,这些环境变量名称的值已在使用前转换成数字。如果指定
了一个环境变量名称,但未在当前环境中定义,那么值将被定为
零。这使您可以使用环境变量值做计算而不用键入那些 % 符号
来得到它们的值。如果 SET /A 在命令脚本外的命令行执行的,
那么它显示该表达式的最后值。该分配的操作符在分配的操作符
左边需要一个环境变量名称。除十六进制有 0x 前缀,八进制
0 前缀的,数字值为十进位数字。因此,0x12 与 18022
相同。请注意八进制公式可能很容易搞混: 0809 是无效的数字,
因为 89 不是有效的八进制位数。(& )
/P 命令行开关允许将变量数值设成用户输入的一行输入。读取输入
行之前,显示指定的 promptString。promptString 可以是空的。
环境变量替换已如下增强:
    %PATH:str1=str2%
会扩展 PATH 环境变量,用 "str2" 代替扩展结果中的每个 "str1"。
要有效地从扩展结果中删除所有的 "str1","str2" 可以是空的。
"str1" 可以以星号打头;在这种情况下,"str1" 会从扩展结果的
开始到 str1 剩余部分第一次出现的地方,都一直保持相配。
也可以为扩展名指定子字符串。
    %PATH:~10,5%
会扩展 PATH 环境变量,然后只使用在扩展结果中从第 11 个(偏
移量 10)字符开始的五个字符。如果没有指定长度,则采用默认
值,即变量数值的余数。如果两个数字(偏移量和长度)都是负数,
使用的数字则是环境变量数值长度加上指定的偏移量或长度。
    %PATH:~-10%
会提取 PATH 变量的最后十个字符。
    %PATH:~0,-2%
会提取 PATH 变量的所有字符,除了最后两个。
终于添加了延迟环境变量扩充的支持。该支持总是按默认值被
停用,但也可以通过 CMD.EXE 的 /V 命令行开关而被启用/停用。
请参阅 CMD /?
考虑到读取一行文本时所遇到的目前扩充的限制时,延迟环境
变量扩充是很有用的,而不是执行的时候。以下例子说明直接
变量扩充的问题:
    set VAR=before
    if "%VAR%" == "before" (
        set VAR=after
        if "%VAR%" == "after" @echo If you see this, it worked
    )
不会显示消息,因为在读到第一个 IF 语句时,BOTH IF 语句中
%VAR% 会被代替;原因是: 它包含 IF 的文体,IF 是一个
复合语句。所以,复合语句中的 IF 实际上是在比较 "before" 和
"after",这两者永远不会相等。同样,以下这个例子也不会达到
预期效果:
    set LIST=
    for %i in (*) do set LIST=%LIST% %i
    echo %LIST%
原因是,它不会在目前的目录中建立一个文件列表,而只是将
LIST 变量设成找到的最后一个文件。这也是因为 %LIST%
FOR 语句被读取时,只被扩充了一次;而且,那时的 LIST 变量
是空的。因此,我们真正执行的 FOR 循环是:
    for %i in (*) do set LIST= %i
这个循环继续将 LIST 设成找到的最后一个文件。
延迟环境变量扩充允许您使用一个不同的字符(惊叹号)在执行
时间扩充环境变量。如果延迟的变量扩充被启用,可以将上面
例子写成以下所示,以达到预期效果:
    set VAR=before
    if "%VAR%" == "before" (
        set VAR=after
        if "!VAR!" == "after" @echo If you see this, it worked
    )
    set LIST=
    for %i in (*) do set LIST=!LIST! %i
    echo %LIST%
如果命令扩展被启用,有几个动态环境变量可以被扩展,但
不会出现在 SET 显示的变量列表中。每次变量数值被扩展时,
这些变量数值都会被动态计算。如果用户用这些名称中任何
一个定义变量,那个定义会替代下面描述的动态定义:
%CD% - 扩展到当前目录字符串。
%DATE% - 用跟 DATE 命令同样的格式扩展到当前日期。
%TIME% - 用跟 TIME 命令同样的格式扩展到当前时间。
%RANDOM% - 扩展到 032767 之间的任意十进制数字。
%ERRORLEVEL% - 扩展到当前 ERRORLEVEL 数值。
%CMDEXTVERSION% - 扩展到当前命令处理器扩展版本号。
%CMDCMDLINE% - 扩展到调用命令处理器的原始命令行。COPY
.


命令概括:

set,意为“设置”。
variable,意为“变量”;
/a,arithmetic,意为“算术”(感谢demon的英文提供)。
/p,prompt,意为“提示”;


参数详解:

先从光杆的set命令说起。

1.显示当前所有环境变量

输入:
setCOPY
.

效果:
ALLUSERSPROFILE=C:\ProgramData
APPDATA=C:\Users\helloworld\AppData\Roaming
CommonProgramFiles=C:\Program Files\Common Files
COMPUTERNAME=HELLOWORLD-PC
ComSpec=C:\Windows\system32\cmd.exe
FP_NO_HOST_CHECK=NO
HOMEDRIVE=C:
HOMEPATH=\Users\helloworld
LOCALAPPDATA=C:\Users\helloworld\AppData\Local
LOGONSERVER=\\HELLOWORLD-PC
NUMBER_OF_PROCESSORS=2
OS=Windows_NT
Path=C:\Program Files\Common Files\Microsoft Shared\Windows Live;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\Common Files\Thunder Network\KanKan\Codecs;C:\Program Files\Windows Live\Shared
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
PROCESSOR_ARCHITECTURE=x86
PROCESSOR_IDENTIFIER=x86 Family 6 Model 15 Stepping 13, GenuineIntel
PROCESSOR_LEVEL=6
PROCESSOR_REVISION=0f0d
ProgramData=C:\ProgramData
ProgramFiles=C:\Program Files
PROMPT=$P$G
PSModulePath=C:\Windows\system32\WindowsPowerShell\v1.0\Modules\
PUBLIC=C:\Users\Public
SESSIONNAME=Console
SystemDrive=C:
SystemRoot=C:\Windows
TEMP=C:\Users\HELLOW~1\AppData\Local\Temp
TMP=C:\Users\HELLOW~1\AppData\Local\Temp
USERDOMAIN=helloworld-PC
USERNAME=helloworld
USERPROFILE=C:\Users\helloworld
windir=C:\WindowsCOPY
.


2.显示以指定字符串开头的环境变量

显示以“p”开头的环境变量。
代码:
set pCOPY
.

效果:
Path=C:\Program Files\Common Files\Microsoft Shared\Windows Live;C:\Windows\syst
em32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v
1.0\;C:\Program Files\Common Files\Thunder Network\KanKan\Codecs;C:\Program File
s\Windows Live\Shared
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
PROCESSOR_ARCHITECTURE=x86
PROCESSOR_IDENTIFIER=x86 Family 6 Model 15 Stepping 13, GenuineIntel
PROCESSOR_LEVEL=6
PROCESSOR_REVISION=0f0d
ProgramData=C:\ProgramData
ProgramFiles=C:\Program Files
PROMPT=$P$G
PSModulePath=C:\Windows\system32\WindowsPowerShell\v1.0\Modules\
PUBLIC=C:\Users\PublicCOPY
.

显示以“path”开头的环境变量。
代码:
C:\Users\helloworld\Desktop>set pathCOPY
.


效果:
Path=C:\Program Files\Common Files\Microsoft Shared\Windows Live;C:\Windows\syst
em32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v
1.0\;C:\Program Files\Common Files\Thunder Network\KanKan\Codecs;C:\Program File
s\Windows Live\Shared
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSCCOPY
.



3.直接给变量赋值

变量有两个属性,一是变量名,二是变量值。

建议使用c语言的变量名命名规则:“只能由数字、下划线、字母构成,且不能以数字开头”!

批处理中变量名不能以数字开头,且变量名中不能含有“=”,其它可以随意(脚本的好处,也是脚本的坏处)。

代码:
@echo off
Set a=hello world
echo %a%
pause>nulCOPY
.

将字符串“hello world”赋值给变量a,并输出变量a的值。

“=”左边是变量名,“=”右边是变量的值。



4.等待用户输入变量值

这一节讲的就是/p参数的常规运用。

代码:
@echo off
net start Schedule
::开启at服务
Set /p stime=请输入定时关机时间(例如:23:59):
at %stime% shutdown /s /t 0
pauseCOPY
.

这个代码的作用就是,等待用户输入一个时间,然后就会在指定时间关机。

前面说过“=”右边的是变量值,但是这里却不是变量值,而是提示信息,用户输入的字符串才是变量值,因为在set 中加了 /p参数!



5.set的计算功能

set的计算功能可以说是set中最繁杂的一种功能,但你不能不承认——它确实很强大。

①.怎么进行加减乘除?
代码:
@echo off
::加
Set /a n1=1+1
::减
Set /a n2=2-1
::乘
Set /a n3=2*3
::除
Set /a n4=8/2
echo 和:%n1%,差:%n2%,积:%n3%,商:%n4%
pause>nulCOPY
.

可以看出,不论进行哪一种算术运算都含有/a参数,其实不仅仅是算术运算,所有的运算都离不开/a参数。

②.怎么求余数(取模)?

批处理中有一项专门用来求余数的运算符“%”。

在命令行下:
C:\Users\helloworld\Desktop>set /a 9%4
1COPY
.

在批处理文件中:
@echo off
Set /a n=9%%4
echo %n%
pause>nulCOPY
.

可能有人会问:“为什么一个运算符,在命令行和批处理文件中会出现不同的写法呢”,其实写法还是没有变的,都是“%”,只不过%符号比较特殊,在批处理中要先进行一次转义(而%又只能用%转义),看到这里可能你还是不明白,这里可以做一个实验——实验要求:输出一个%。

在命令行下:
C:\Users\helloworld\Desktop>echo %
%COPY
.

在批处理文件中:
@echo off
echo %%
pause>nulCOPY
.


③.复合算术运算符

复合运算符一共有10个,其中复合算术运算符有5个,它们分别是“+=,-=,*=,/=,%=”。

复合运算符只要使用得当,可以很好的节省代码量。

先看一个例子:

计算1-100这100个数字的和。
@echo off
Set n=0
for /l %%i in (1 1 100) do Set /a n=n+%%i
echo %n%
pause>nulCOPY
.

这个代码中Set /a n=n+%%i,第二个n的两边没有“%”,按照常规,变量在引用时,要在变量名两边加上“%”——set /a的特性就是在引用变量时,可以省略 “%”(当然你也可以不省略——但强烈建议你省略)。

用复合算术运算符简写:
@echo off
Set n=0
for /l %%i in (1 1 100) do Set /a n+=%%i
echo %n%
pause>nulCOPY
.

对比两个代码,唯一的差别就是 n=n+%%i 与 n+=%%i。

难道n+=%%i就是 n=n+%%i的意思?

事实上也是如此,而且5个复合算术运算符都是这种意思。

“变量1 复合运算符 变量2” 就等于“变量1=变量1 对应的算术运算符 变量2”。

例如:
n*=3 就是 n=n*3。


建议新手跳过第④小节的讲解,免得转的头晕。

④.位运算符

前面讲解的运算符都是对于字节的运算,但是位运算符却是对于更小的单位——位,进行运算(1字节=8位)。

进行位运算符的学习,需要对2进制有所了解,懂得简单的 10进制 to 2进制 的相互转换,而且要对原码、反码、补码的概念有所了解。

10进制=(8位)2进制补码:

9=0000 1001
5=0000 0101
-9=1111 0111

④.1.按位与运算符(&)

没错,它和and(echo hello & echo world)一摸一样,但是在此处它是按位与(Set /a 9^&5)。

这里,为了方便后面的教学,我们暂且将1称为真,0称为假。
C:\Users\helloworld\Desktop>set /a 9^&5
1
C:\Users\helloworld\Desktop>set /a -9^&5
5COPY
.

为什么写成^&?

跟前面的求余数运算符是一样的道理,由于&符比较特殊,所以需要转义(%必须由%转义,&必须要^转义)。

9和5、-9和5按位与的结果分别为1,5,Why?

位运算就是要用10进制数对应的二进制补码进行运算,然后再将运算得到的二进制补码换算成10进制数输出(这是计算机本身特性决定的,不知道你还记不记的大明湖畔的夏雨荷——计算机科学的基础就是:0,1)。

9: 0000 1001
&
5: 0000 0101
---------------------
1: 0000 0001

-9:1111 0111
&
+5:0000 0101
---------------------
+5:0000 0101

按位与运算,就是“同真为真,其余为假”,在同一位上都是1运算结果才是1,其余都是0.


④.2.按位或运算符(|)

“|”符号在set /a 之外还有“管道”的用法,但是在set /a 中它只是按位或(由于|符号的特殊性,在运用时也要在前面加转义符——^|)。


.
C:\Users\helloworld>set /a 5^|9
13
C:\Users\helloworld>set /a 5^|-9
-9COPY
.


9: 0000 1001
|
5: 0000 0101
---------------------
13: 0000 1101

-9:1111 0111
&
+5:0000 0101
---------------------
-9:1111 0111


按位或运算,就是“一真便真,全假才假”,同一位上只要一个是1,那结果就是1,只有全部是0,结果才是0.

结合前面的按位与(&)运算来看,其实按位与(&)和按位或(|)就是一种比较运算,比较同一位上的0或1的异同,得出结果。


④.3.逻辑移位

逻辑移位运算符有两个:<< ,>>,分别表示向左移位,向右移位。

向左移位(<<)
C:\Users\helloworld\Desktop>set /a 9^<^<2
36COPY
.


9: 0000 1001
<<
2
---------------------
36: 0010 0100  

把二进制补码向左移动两位(不足的在右边补零),然后换算成10进制数得出结果(向左移是将数变大)。

语法:set /a 被移数<<移位数


计算公式:结果=被移数*(2的移位数次方)

例如:9<<2 == 9*(2的2次方) ==36



向右移位(>>)
C:\Users\helloworld\Desktop>set /a 9^>^>2
2COPY
.


9: 0000 1001
>>
2
---------------------
2:  0000  0010

把二进制补码向右移动两位(多余的剔除——这里剔除了最后一个1),然后换算成10进制数得出结果(向右移是将数变小)。

语法:set /a 被移数>>移位数


计算公式:结果=被移数/(2的移位数次方)

例如:9>>2 == 9/(2的2次方) == 2

逻辑移位运算符的特性可以加以利用,来计算数值的偶数倍、偶数半:


比如 9 的 2倍,即 Set /a 9^<^<1

比如 9 的 1/2,即 Set /a 9^>^>1



④.4.按位异或运算符(^)
按位异或运算符也是个特殊符号(转义符),所以在使用的时候也要转义(^^)。
C:\Users\helloworld\Desktop>Set /a 9^^5
12
C:\Users\helloworld\Desktop>Set /a -9^^5
-14COPY
.



9: 0000 1001
^
5: 0000 0101
---------------------
12: 0000 1100

-9:1111 0111
^
+5:0000 0101
---------------------
-14:1111 0010

按位异或运算,就是“不同为真,相同为假”,相同位都是1或都是0,结果就是0,其余结果都是1.




④.5.复合位运算

结合前面的复合算术运算符和位运算符,复合位运算就不难理解。


例如:(&=)运算符
@echo off
Set n1=9
Set /a n1^&=5
echo %n1%
pauseCOPY
.

结果为1。

所以,“n1^&=5”就相当于“n1=n1^&5”(“&”需要转义)。

同理,“ n1^^=5”就相当于“n1=n1^^5”;"n1^|=5"就相当于“n1=n1^|5”

"n1^<^<=2"就相当于“n1=n1^<^<2”.

位运算就在这里结束了,其中“! ~ -   ”这三个 “一元运算符”都没有讲解。



6.逗号运算符

如果两个变量的值都是数字,而不是字符串,就可以用set /a 中的逗号运算符一次性赋值。

例子:
@echo off
Set /a a1=5,a2=5
echo %a1% %a2%
pauseCOPY
.

结果:
5 5COPY
.

如果变量值是字符串,用这种方法就会出错。

例如:
@echo off
Set /a a1=5,a2=5a
echo %a1% %a2%
pauseCOPY
.

结果:
无效数字。数字常数只能是十进制(17),十六位进制(0x11)或
八进制(021)。
5COPY
.

只输出了a1的值,a2没有输出,因为a2的值是字符串。

看起来像字符串的16进制数。

例如:
@echo off
Set /a a1=5,a2=0x15
echo %a1% %a2%
pauseCOPY
.

结果:
5 21COPY
.

“0x15”中0x是16进制数前缀(等于10进制数21)。
"015"中0是8进制数前缀(等于10进制数13)。



7.替换变量中的字符串

①.将变量中指定字符串替换成其它字符串

例如:
将字符串中的“o”替换为“-”。
@echo off
Set str=helloworld
Set str=%str:o=-%
echo %str%
pauseCOPY
.

结果:
hell-w-rld
请按任意键继续. . .COPY
.


②.异样替换,删除变量中的指定字符串

删除变量中的指定字符串其实就是将指定字符串替换为空值。

例如:
将字符串中的“o”删除。
@echo off
Set str=helloworld
Set str=%str:o=%
echo %str%
pauseCOPY
.

结果:
hellwrld
请按任意键继续. . .COPY
.

字符串替换还支持通配符“*”。
例如:
将第一个字符“o”前面的字符(包括“o”)全部删除。
@echo off
Set str=helloworld
Set str=%str:*o=%
echo %str%
pauseCOPY
.

结果:
worldCOPY
.


8.截取字符串

截取字符串就是将一个字符串中指定的部分提取出来。

例如,我要截取字符串“一二三四五六七八九十”中的“三四五”,有四种写法:
@echo off
Set a=一二三四五六七八九十
Set a1=%a:~2,3%
Set a2=%a:~2,-5%
Set a3=%a:~-8,3%
Set a4=%a:~-8,-5%
echo %a1% %a2% %a3% %a4%
pauseCOPY
.

为什么这四种写法都能实现要求?
要解释会有很多种说法,我这里只能给出一句记忆口诀:
第一数,起始点。正左右,负右左。偏移!
第二数,结束点。正左右,负右左。终止!


解释第一句:“第一数,起始点。正左右,负右左。”就是“第一个数是起始点,如果是正数就从左往右数,如果是负数就从右往左数”。

以这一句为例,“Set a1=%a:~2,3%”

2是第一个数,而且是正数,所有从左往右数2个数:一二,“偏移!”就是移位。——起始点!

3是第二个数,也是正数,所有也从左往右数(从起始点开始数)3个数,三四五,“终止”!——终止点!


9.“输入光杆set,不会显示出来的”环境变量

%CD% - 扩展到当前目录字符串。

%DATE% - 用跟 DATE 命令同样的格式扩展到当前日期。

%TIME% - 用跟 TIME 命令同样的格式扩展到当前时间。

%RANDOM% - 扩展到 0 和 32767 之间的任意十进制数字。

%ERRORLEVEL% - 扩展到当前 ERRORLEVEL 数值。

%CMDEXTVERSION% - 扩展到当前命令处理器扩展版本号。

%CMDCMDLINE% - 扩展到调用命令处理器的原始命令行。














扩展阅读:

返回列表