.bat批处理(八):各种形式的变量%0、%i、%%i、var、%var%、!var!的含义和区别

2023-11-08

前言

最近使用批处理程序处理文件的时候,发现这 bat中的变量形式真是“变化多端”,有时候加1个百分号%,有时候加2个百分号%%,还有的时候加感叹号!,真是让初学者一头雾水,于是查询资料做了一些小测试,终于大致弄清楚了这些变量的含义,接下来一一列举出来。

变量对比

下面通过一些具体的例子来看下标题中提到的这些变量什么时候使用,使用的时候有哪些注意事项。

%0

这个是批处理程序中的固定用法,类似于C++程序main函数中argv变量数组,类比可以知道,argv[0]表示exe程序的文件名,argv[1]表示启动程序的第1个参数,后面依次类推。而在批处理程序中%0表示这个批处理程序的文件名,%1表示调用这个批处理时传入的第1个参数,%2表示调用这个批处理时传入的第2个参数,最大可以到%9,具体用法可以参考之前的总结《.bat批处理(二):%0 %1——给批处理脚本传递参数》,简单测试如下:

@echo off

echo param0=%0
echo param0=%1
echo param0=%2

将上述代码保存在文件testparams.bat中,从cmd命令行运行批处理文件,只传入一个参数,运行结果如下:

C:\Users\Administrator\Downloads>testparams.bat “hello world”
param0=testparams.bat
param1=“hello world”
param2=

%i

在题目所列的这些变量中,这一个比较特殊,因为它不是批处理文件中的变量,只能用于cmd命令行下的for循环中,在命令行中for循环的语法是for %variable in (set) do command [command-parameters],其中的variable只能是单字母或者非特殊含义的字符,同样的for循环语句如果写在批处理文件中variable之前就要加两个%%了,先来看看%i的用法,直接在命令行中遍历集合打印输出:

C:\Users\Administrator\Downloads>for %i in (1,3,5,8) do echo %i
C:\Users\Administrator\Downloads>echo 1
1
C:\Users\Administrator\Downloads>echo 3
3
C:\Users\Administrator\Downloads>echo 5
5
C:\Users\Administrator\Downloads>echo 8
8

如果将其中的%i改成%%i,就会报语法错误,测试结果如下:

C:\Users\Administrator\Downloads>for %%i in (1,3,5,8) do echo %%i
此时不应有 %%i。

%%i

这种类型也是for循环中特有的,与%i相对,属于批处理程序的用法,换句话说就是在for循环中遍历的索引变量,如果在命令行中定义需要一个%,如果相同的语句定义在批处理文件中需要2个%%,语法为for %%variable in (set) do command [command-parameters],variable同样只能是单个字母或者普通字符,至于为什么同样含义的变量在批处理中要多加一个%,至今也没有找到官方的说法,查找MSDN也没有发现说明,不过就我个人理解可能就像我们在命令行中打印一个%,可以正常打印输出,如果通过printf()想输出%就需要2个%的原理一样吧,测试如下:

for %%i in (1,3,5,8) do echo %%i

运行结果:

C:\Users\Administrator\Downloads>testfor.bat
C:\Users\Administrator\Downloads>for %i in (1 3 5 8) do echo %i
C:\Users\Administrator\Downloads>echo 1
1
C:\Users\Administrator\Downloads>echo 3
3
C:\Users\Administrator\Downloads>echo 5
5
C:\Users\Administrator\Downloads>echo 8
8

观察运行结果发现,运行批处理文件的时候,实际上去掉了%%i变量的1个%,将文件中代码改为1个%试下:

for %i in (1,3,5,8) do echo %i

运行结果:

C:\Users\Administrator\Downloads>testfor.bat
此时不应有 i。

var

这个变量看起来挺正常的,也没有那么多奇奇怪怪的字符,和Lua、Python等语言中的变量长得挺像,实际上变量的这种形式很“短暂”,一般只能出现在给变量赋值的时候,也就是set语句之后,作为左值接受赋值时,或者在等号右测可评估的表达式中,举个例子,编写下面代码保存在normalVar.bat中:

@echo off

set var1=1
set /a var2=var1+1

echo var1
echo var2

运行之后的结果为:

C:\Users\Administrator\Downloads>normalVar.bat
var1
var2

看完结果之后觉得很神奇是不是,为什么和我学的其他语言不一样呢,我使用set分别为var1和var2赋了值,但是输出的时候居然不是数字而是变量名,其实这就引出了之后%var%这种用法,接着往下看。

%var%

在批处理中除了上面所说的在set语句后面的两种情况,再要想引用变量就需要在变量两端各加一个百分号%,明确的告诉引用者这是一个变量,使用时需要评估一下值,而不要当成字符串,上一个例子中echo后面想要输出的变量没有加%,那就被当成一个字符串处理,原样输出了,修改上个例子如下:

@echo off

set var1=1
set /a var2=var1+1

set var3=%var2%

echo %var1%
echo %var2%
echo %var3%

运行之后运行结果入下:

C:\Users\Administrator\Downloads>normalVar.bat
1
2
2

看了这次的结果感觉正常多了,有一点需要注意,set var3=%var2%这一句中var2变量中的%不能省略,因为它既不属于左值也不属于被评估值的表达式,如果不加%,赋值后var3的值会变成“var2”这个字符串。

!var!

这是最后一种常见的变量形式,同时也是一种不太好理解的形式,需要记住一点,这种变量与延迟环境变量扩展有关,如果没开启延迟环境变量扩展,那么!var!就是一个普通的包含5个字母的字符串,如果开启了延迟环境变量扩展,那么它就是变量var的实际值,可能说到这有的人会产生疑惑,引用变量var的值不是使用%var%吗?那么在开启延迟环境变量扩展的情况下,%var%和!var!有什么区别呢?下面举个例子测试下,编写如下代码保存在extVar.bat文件中:

@echo off

set var1=110
set var1=120&echo %var1%

运行之后的结果为:

C:\Users\Administrator\Downloads>extVar.bat
110

看到结果的时候是不是再次怀疑了世界,在打印变量var1之前明明重新赋值了120,为什么打印出来还是110呢?其实这是批处理脚本执行机制导致的,它会按行执行,在执行之前会先预处理,当执行set var1=110之后,变量var1变成了110,在执行set var1=120&echo %var1%之前先预处理,将变量%var1%替换成了110,然后语句变成了set var1=120&echo 110,所以就得到了我们上面测试的结果。

想要解决这个问题就需要开启延迟环境变量扩展,语句为setlocal enabledelayedexpansion,然后将引用变量的形式由%var1%改为!var1!即可,所以可以修改代码如下:

@echo off

setlocal enabledelayedexpansion
set var1=110
set var1=120&echo !var1!

运行之后的结果为:

C:\Users\Administrator\Downloads>extVar.bat
120

这回输出的结果符合预期了,开启了延迟环境变量扩展之后,!var!形式的变量在用之前才会评估确切的值,这是一个知识点,也是一个易错点,特别是在for循环中要格外注意,因为for循环语句的循环体括号中,所有的操作被看成是同一行,所以经常会用到延迟环境变量扩展。

总结

  1. for循环在cmd命令行中的固定用法for %i in (set) do (...),循环变量格式为%i
  2. for循环在bat处理程序中的固定用法for %%i in (set) do (...),循环变量格式为%%i
  3. 至于为什么for语法在批处理中需要多写一个%,希望知道的小伙伴能给出答案和参考资料,不胜感激
  4. 想要变量被使用的时候再评估值需要开启延迟环境变量扩展,语法为setlocal enabledelayedexpansion,同时使用!var!形式的变量
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

.bat批处理(八):各种形式的变量%0、%i、%%i、var、%var%、!var!的含义和区别 的相关文章

  • JavaScript - 使用 new 关键字的标准

    这是一个与内存使用和 new 关键字有关的问题 我需要您对在本地方法中使用 新 的建议和偏好 get function var get new Ajax Updater resourceList url method POST onComp
  • 如何设置定时器

    有什么办法可以将计时器设置为 60 秒xor ah ah Enter Again xor ah ah I should put 60 seconds here int 16h The user should press S before 6
  • Jquery 如果它是第一次单击元素

    我需要我的脚本在第一次单击元素时执行某些操作 并在单击 2 3 4 等时继续执行不同的操作 selector click function I would realy like this variable to be updated var
  • DOS批处理脚本转换字符串2十六进制

    如何在 DOS 批处理脚本中将字符串转换为十六进制 例如 将 abcd 转换为 61626364 因为 a 是 0x61 我尝试从网络上寻找解决方案 一天 但找不到我的答案 echo off setlocal EnableDelayedEx
  • Swift:模型结构,使用选项与空值初始化

    In Swift 比如说我有一个struct为了这model struct Message var message String var timestamp String var id String 我会实例化多个Messages使用这个s
  • 在程序集中写入文件时出现问题

    我正在尝试用汇编语言编写一个简单的程序 在其中打开一个现有文件并在其中写入一条消息 这是我在数据段中定义的消息 当我想写入文件时会出现问题 在我尝试写入后 AX 寄存器将包含 5 诺顿专家指南称这是 拒绝访问 错误代码 关于我做错了什么有什
  • 重新运行时将 Unicode 参数传递给 Windows .bat 文件

    我的 bat 文件如下所示 echo off CD D dp0 if 2 set user USERNAME else set user 2 getFile if 1 set p file Enter file name else set
  • 如何在 DOS 汇编中正确挂接中断 28h 并恢复它?

    我试图将中断28h的处理程序设置为我自己的例程 恢复所有涉及的寄存器和标志 并恢复原始的中断处理程序 我在 VirtualBox 中的 DOSBox 和 MS DOS 6 22 下使用 NASM Assembler 我考虑过调试 但在 TS
  • 以管理员身份运行批处理文件 - Windows 7 - 从网络文件系统命令“运行方式”

    我需要设置程序安装程序的交付 该程序有一个program installer exe 和一个文件夹 我在创建安装程序时无法将其包含在安装程序中 因此 当用户需要安装该程序时 我通过邮件向他发送一个批处理文件 echo off if DEFI
  • 8086汇编程序存储唯一值

    我一直在制作这个程序 它接受一个列表并在其中查找唯一元素并将其存储在另一个列表或寄存器中 下面的代码将主列表放入 SI 寄存器中 然后 BX 充当指针 遍历整个数组以查找相似之处 如果没有找到相似之处 则 SI 中的元素 存储在 AL 中
  • 从 DOS 命令行关闭正在运行的应用程序

    start 命令可以在批处理文件中启动像记事本这样的应用程序 如下所示 start notepad start my love mp3 但是如何从命令行关闭正在运行的应用程序呢 我发现taskkill在我的搜索中 但我认为这不是正确的命令
  • 我对 for 循环中的 javascript let 和 var 感到困惑? [复制]

    这个问题在这里已经有答案了 这是我的循环代码 var username Sam Adarsh Rohit Rajat for var i in username console log username i 它的输出与需要的相同 但我不确定
  • 为回归方程选择适当的滞后以及如何解释 VARselect 结果

    我的问题有两个方面 如何为回归方程选择合适的滞后 我有房价的因变量 以及租金 房屋供应 国家股市指数 抵押贷款利率和房屋空置率的自变量 我读了一些书 发现VARselect data lag max 1 or 2 or 3 etc 可以帮助
  • JMeter - 使用其他 BeanShell 预处理器/后处理器中的变量?

    有没有一种方法可以将变量从一个 BeanShell 预处理器 后处理器引用到另一个 BeanShell 处理器 它们在同一个线程组内 如果我在 HTTP 请求下的 BeanShell 预处理器内创建一个字符串变量 那么我可以在同一 HTTP
  • 如何使用dos批处理文件命令将日期设置为当前日期

    如何使用 dos 批处理文件命令将日期设置为当前日期 如果您需要在批处理文件中使用当前日期 则变量 date 有当前日期 echo date 23 02 2010 它使用您计算机的区域设置的格式 在我的电脑里是dd mm yyyy 自从 不
  • 在汇编程序中将十进制转换为二进制

    我的第一个汇编程序需要帮助 我必须将用户输入的值从十进制转换为二进制 我不知道如何将值显示为小数 以及下一步应该做什么 谁能一步一步指导我下一步做什么 model small stack 100h data txt1 db Enter bi
  • 在 x86 程序集中将整数打印到控制台

    当我在 16 位汇编中添加两个值时 将结果打印到控制台的最佳方法是什么 目前我有这个代码 CODE START mov ax 1 put 1 into ax add ax 2 add 2 to ax current value mov ah
  • 在 JavaScript 中引用 C# 变量

    我已经阅读了很多线程 但我不明白为什么这不起作用 我正在创建一个将用作导航栏的 SharePoint Web 部件 一切都很顺利 直到我尝试在 JS 代码中引用 C 变量 这是来自 VisualWebPart1UserControl asc
  • 使用 Python 自动化旧的 DOS 应用程序

    有没有办法从Python 在Windows上 自动化旧的DOS应用程序 16位 可能需要模拟器 例如DOSBox 我想将密钥和字符串发送到应用程序 检测 DOS 屏幕 的更新并获取应用程序输出 如果 DOS 应用程序能够 隐藏 运行 即不显
  • 使用 GNU C 内联汇编在 VGA 内存中绘制字符

    我正在学习使用 C 和内联汇编在 DOS 中进行一些低级 VGA 编程 现在我正在尝试创建一个在屏幕上打印出字符的函数 这是我的代码 This is the characters BITMAPS uint8 t characters 464

随机推荐