03 Windows批处置惩罚的作用域和延长扩展

打印 上一主题 下一主题

主题 1649|帖子 1649|积分 4947

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
在前文中,我们学习了变量、如何设置它们以及如何剖析它们的值。在本文中,我将重点先容setlocal命令,它是批处置惩罚中非常紧张的、具有差别特性的核心内容,它可以何时、何地以及如那边置惩罚变量。起首,它界说了作用域:在那边以及何时可以访问和操纵这些变量。其次,它启用了一个称为延长扩展的特性,该特性改变了变量剖析的方式,其效果之一是允许将一个变量存储在另一个变量中。
全部语言都以某种方式处置惩罚作用域,但延长扩展或类似的东西远不常见,您将看到它的一些令人惊讶的用途。最后,setlocal命令启用命令扩展,用于描述为很多其他批处置惩罚命令打开的大量附加功能。
作用域

作用域界说变量的生命周期。全局变量可以在任何地方设置、剖析、删除和修改,这对于大多数简单的bat文件都很有效。局部变量具有有限的保存期限,意味着可以在其作用域内的单个代码段中访问。如果这些修改不能被识别,那么变量就超出了作用域。
在批处置惩罚中,setlocal命令之后开始一段代码,此中变量在作用域中,endlocal命令结束该部分,使这些变量不在作用域中。这两个命令之间界说或操纵的全部内容在该空间中都是活动的,但是在实行endlocal命令之后,这些变量将恢复到先前的状态。
为了演示,下面的代码将三个变量的状态分别写入setlocal命令作用域内和作用域外的控制台。一个仅在setlocal作用域内界说,一个仅在setlocal作用域外界说,另有一个既在setlocal作用域内又在setlocal作用域外界说。在echo命令的右侧,我们包含了显示效果的注释,特别是写入控制台的已剖析变量:
  1. set inAndOut=OUT
  2. set outer=OUT
  3. setlocal
  4. set inAndOut=IN
  5. set inner=IN
  6. > con echo Inside Scope:        & rem Inside Scope:
  7. > con echo Outer  Variable = %outer%        & rem  Outer Variable = OUT
  8. > con echo Inner  variable = %inner%    & rem  Inner Variable = IN
  9. > con echo In/Out Variable = %inAndOut% & rem In/Out Variable = IN
  10. endlocal
  11. > con echo Outside Scope:        & rem Outside Scope:
  12. > con echo Outer  Variable = %outer%        & rem  Outer Variable = OUT
  13. > con echo Inner  variable = %inner%    & rem  Inner Variable =
  14. > con echo In/Out Variable = %inAndOut% & rem In/Out Variable = OUT
复制代码
这里有很多东西要拆解。让我们看看界说的第一个变量:inAndOut在setlocal命令实行之前被设置为OUT,这意味着它被设置在命令的作用域之外。setlocal实行后,该变量会被设置为IN。当inAndOut第一次被询问时,它会被剖析为IN,由于它在作用域中。但是在endlocal程序实行之后,它就不在作用域范围内,并恢复到之前的状态,也就是OUT。
现在考虑内部变量,它在作用域中只界说一次。也就是说,实行完setlocal命令的时候,它被设置为IN。在endlocal语句实行之前,这个变量会被剖析成IN,但风趣的是;在endlocal语句之后,它恢复到之前没有界说的状态,即null或empty。
最后一个变量是外部的,它也只界说一次,但是当它超出作用域时。在setlocal实行之前,它被设置为OUT。正如你所料,在endlocal程序实行后,当它超出作用域时,这个变量仍旧是OUT。但你可能没有预料到,它的值在setlocal 的范围内也是可用的,由于它的值在endlocal实行之前也是OUT !
这个例子表明setlocal命令并没有阻止我们使用已经在作用域中的变量。在此之前存在的全部东西仍旧可用。它的作用是如许的:在setlocal实行的那一刻对环境举行快照,并在endlocal实行时返回该快照。
使用setlocal和endlocal命令界说作用域只有一个用途,但它很紧张:在代码的一部分中隐藏或分割变量以防止冲突。默认情况下,批处置惩罚变量是全局的;在一个bat文件中设置的变量可以在bat的文件中剖析或重置。默认情况下,很多其他语言使用相反的方法,限制被调用程序和例程内部使用的变量的范围。有时全局变量非常好,但在其他情况下,限制作用域是更好的选择。界说范围的本领使我们可以或许使用最适合我们的应用程序的功能。
如果您正在编写一个将被很多其他进程调用的实用程序bat文件,那么您可能不知道调用进程正在使用哪些变量。在bat文件的顶部放置一个setlocal,在末尾或靠近末尾放置一个endlocal,可以界说和限制作用域。如许做的效果是,如果您碰巧使用了与调用bat文件相同的变量名,那么您就不会踩到它的变量,这就允许调用者调用您的bat文件,并保证不会产生不良副作用。对于所谓的内部例程也是如此。
界说作用域提出了一个风趣的问题。如果调用实用程序bat文件来实行特定任务,那么该任务的至少一部分很可能是设置和返回某个变量。有一种方法允许一个或多个变量在endlocal命令中存活,我将在后面举行先容。
延长扩展

setlocal命令是一个多管齐下的工具。除了界说作用域外,当与描述性参数一起使用时,它还支持延长扩展:
  1. setlocal EnableDelayedExpansion
复制代码
延长扩展实现了两轮变量剖析:初始剖析和延长剖析或扩展。当解释器实行一个bat文件时,它逐个处置惩罚每一行代码,起首读入或剖析一行,然后实行该行。初始剖析发生在解释器剖析该行时,延长扩展发生在它实行该行时。
这个特性允许一些在大多数语言中没有的风趣举动。比方,可以将变量的值视为变量本身,也可以将其值视为另一个变量名的一部分。在下面的代码中,Toyota既是一个变量名又是一个值;固然这不仅仅是巧合。
  1. setlocal EnableDelayedExpansion
  2. set Car=Toyota
  3. set Toyota=Prius
复制代码
设置启用延长扩展的Car和Toyota
起首,我们需要使用带有参数的setlocal命令来启用延长扩展。接下来,我们将Car设置为汽车的品牌,在本例中是Toyota。但是丰田生产几个车型,如果我们想捕获一个特定的车型,我们可以将界说为Toyota的变量设置为值Prius。
变量及值

正如前面提到的,丰田既是一个值也是一个变量。它是Car变量的值,也是一个包含Prius值的变量。现在我们可以实行三条语句,将三个变量写入控制台,如下所示。
  1. ...
  2. > con echo               Car = %Car%
  3. > con echo         Car Again = !Car!
  4. > con echo Delayed Expansion = !%Car%!
复制代码
通过三种差别的方式剖析Car;输出效果如下:
  1.               Car = Toyota
  2.         Car Again = Toyota
  3. Delayed Expansion = Prius
复制代码
到现在为止,Car的第一种方式是常规剖析。在变量周围加上百分号(%)将其剖析为其值Toyota。第二个命令引入了一些新东西:感叹号(!)用作分隔符来剖析变量!Car!,而不是百分号。用感叹号包围的变量也剖析为Toyota,但是为什么要用两个差别的字符来实行相同的功能呢?在我们检查最后的命令之后,答案就会出现。
第三个命令真正显示了延长扩展的功能。变量被百分号包围,百分号被感叹号包围。解释器起首将%Car%剖析为Toyota,该值现在被感叹号包围,这将导致它再次被剖析,因此!Toyota!变为Prius。把全部这些放在一起,变量剖析如下:
!%Car%! → !Toyota! → Prius
为了答复关于两个差别字符实行相同功能的问题,解释器需要同时实行此剖析,由于我们现在有两轮剖析:百分号用于内部剖析,感叹号用于外部剖析。(那么这里我们可以使用两个百分号大概两个感叹号大概%!Car!%来剖析吗?)
同理,我们也可以关闭延长扩展(删除setlocal EnableDelayedExpansion)来观察控制台输出:
  1.               Car = Toyota
  2.         Car Again = !Car!
  3. Delayed Expansion = !Toyota!
复制代码
如果没有延长扩展,感叹号将被剖析为普通文本,对批处置惩罚没有意义。!Car!变量根本没有被剖析;解释器甚至不认为这三个字母是一个变量。!%Car%!变量履历了一轮百分号转换,但是再次转换,感叹号只是直接输出。
在前一篇文章关于变量和值中,我们巧妙地回避了一个问题,即变量名不应该以数字开头。从技术上讲,你可以设置如许一个变量,但你不能用百分号来剖析它;您只能使用感叹号和启用延长扩展来实行此操纵。处置惩罚这个小问题的最好方法是永远不要以数字作为变量名的开头。
现在我们有了一个变量,它可以被剖析为一个值,而这个值在第二次被剖析为另一个值。在那些花哨的当代编译语言中,这通常不轻易做到,甚至根本做不到。说实话,只管整个词既是变量又是值可能很酷,但它在实际世界中并不常用,但部分变量名有很多应用。
部分变量名

当剖析的值仅用作变量名的一部分时,这种技术变得更加风趣和有用。为了证明这一点,请考虑以下五个城市的标志性烹饪佳构:
  1. set foodNash=Hot Chicken
  2. set foodNYC=Thin Crust Pizza
  3. set foodChic=Deep Dash Pizza
  4. set foodNO=Muffuletta Sandwich
  5. set foodSTL=Frozen Custard
复制代码
每个变量名(由食物和城市的常见缩写组合而成)都被设置为该城市著名的菜肴。这里只显示了五个变量,但是您可以界说任何数量。
下面的一组变量具有这五个城市的相同缩写,此中每个都添加了Full并分配了该城市的全名:
  1. set NashFull=Nashville
  2. set NYCFull=New York City
  3. set ChicFull=Chicago
  4. set NOFull=New Orleans
  5. set STLFull=St Louis
复制代码
现在用两个延长扩展的例子来探讨这个echo命令:
  1. > con echo  The best !food%city%! can be found only in !%city%Full!
复制代码
如果city设置为NO,并且启用了延长扩展,则该命令将以下内容写入控制台:
  1. The best Muffuletta Sandwich can be found only in New Orleans.
复制代码
为了明白这是如何工作的,让我们先来看看!food%city%!变量。内部变量city及其包围的百分号被剖析为NO,从而显示foodNO变量。接下来,感叹号分隔符将其剖析为三明治。总结流程如下:
!food%city%! → !foodNO! → Muffuletta Sandwich
同样,城市的全名也分两步剖析。这里唯一的区别是变量名的硬编码部分位于要剖析的部分后面:
!%city%Full! → !NOFull! → New Orleans
对于差别的city值,echo命令的举动是差别的。当变量分别被设置为NYC、Nash、Chic和STL时,它会向控制台写入以下四句话:
  1. The best Thin Crust Pizza can be found only in New York City.
  2. The best Hot Chicken can be found only in Nashville.
  3. The best Deep Dish Pizza can be found only in Chicago.
  4. The best Frozen Custard can be found only in St Louis.
复制代码
在本节的开头,我建议将已剖析的值作为变量名的一部分更有用。这个例子就是是典范的,但您可以很轻易地将该技术扩展到更实用的东西。在专业范畴,而不是以城市为中心的烹饪范畴,您可以创建一组变量来界说基于位置将文件传输到差别的路径,比方pathNYC、pathNash和pathSTL。然后,复制文件的单个命令可以使用相同的延长扩展技术将文件传输到多个目的地之一。
有创造力的程序员似乎可以无穷地使用延长扩展,当我们在后续讨论数组和哈希表时,我们将讨论此中的一些用途。后文中的for命令将在很大程度上依赖于延长扩展,一个变量将可以或许同时保存两个值也是值得我们讨论的。
命令扩展

setlocal命令还接受一个参数,用于打开命令扩展。与延长扩展差别,命令扩展默认情况下应该是开启的,但您也可以使用以下命令显式地打开它们:
  1. setlocal EnableExtensions
复制代码
开启命令扩展可以为几个批处置惩罚命令解锁大量附加功能和可用选项。比方,for命令对于任何批处置惩罚程序员都是必不可少的。我们还没有讨论它,但是当命令扩展被禁用时,批处置惩罚有一个for命令的变体。甚至在前文中讨论的set命令也有附加的功能和可用的选项。具体的特性因命令而异,您可以通过help命令在命令提示符处检索它们的详细信息。
为了演示通过启用命令扩展为一个命令解锁的额外功能,返回到命令提示符并从前面输入相同的命令来检索set命令的文档:
  1. help set
复制代码
在简短的几行文本之后,详细说明命令扩展未启用时命令的作用,解释器显示以下行:
  1. 如果命令扩展被启用,SET 会如下改变:
复制代码
下面是全部已解锁的扩展功能。有太多的信息要展示,但在这个小的案例中,两个以前不可用的选项是共享的:
  1. 在 SET 命令中添加了两个新命令行开关:  
  2. SET /A expression
  3. SET /P variable=[promptString]
复制代码
我在前面的文章中提到了这些选项,但是没有提到命令扩展可以打开它们。在启用命令扩展时,help命令提供的关于set命令功能的信息是禁用命令扩展时的,对于很多其他命令也是如此。随着我们先容更多命令,我鼓励您使用help命令进一步研究它们,以查看更多的用法和选项列表,并查看命令扩展名启用了哪些功能。
setlocal和endlocal的结论

在编写了几年的bat文件之后,我对setlocal和endlocal命令的使用有一些剧烈的看法,并且我并不羞于分享它们。我编写的每个高级bat文件在代码的第一行或第一行附近都有这个命令:
  1. setlocal EnableExtensions EnableDelayedExpansion
复制代码
我将高级bat文件界说为不能从另一个bat文件调用的bat文件。我很少遇到不希望启用命令扩展和延长扩展的情况。这些额外的功能险些不需要任何成本。就似乎你可以把你的丰田变成兰博基尼,没有任何缺点,比如成本和汽油里程。但在这种稀有的情况下,您可以使用DisableExtensions和DisableDelayedExpansion参数禁用这些特性。
此外,每当编写一些可能对其他代码产生不利影响的逻辑时,我都会在该逻辑之前使用不带参数的简单setlocal命令,并用相应的endlocal命令结束它。别担心;延长扩展仍旧从原来的setlocal命令启用。您甚至可以嵌套多个setlocal和endlocal命令,在子节中创建具有界说范围的代码子节,但深度不高出32层。我从来没有靠近过这个限制,但是如果您如许做,您可以在调用的例程或另一个bat文件中进一步嵌套。
为了完备起见,最幸亏bat文件的末尾设置一个相应的endlocal,但如果省略,解释器将在退出高级bat文件之前实行一个隐含的endlocal。
至关紧张的是,本系列文章是在假设命令扩展和延长扩展都启用的情况下誊写的。如果文章中的示例在您的测试中不起作用,请确保您已经运行了带有两个启用参数的命令。
紧张:
对于前面提到的使用特定的setlocal命令启动全部高级bat文件的规则,只有一个例外。在后面的文章中,我将提供一些非常短的bat文件的例子,可能只有两到三行。这些简单的示例可能不需要这个命令,并且它的使用可能会将重点从手头的主题转移开。在这些情况下,我将不包括该命令,但要明白它一直都在那边。
总结

本文的主要内容是setlocal命令,它界说了作用域并启用命令扩展。最紧张的是,它支持延长扩展,为界说和使用变量提供了巨大的可能性。
启用延长扩展后,您看到了如何根据界说城市的变量的值,仅用一个命令就可以写出五个句子中的一个。但是,如果延长睁开被禁用,您可能需要使用5个if命令来查询该变量。在本文给出的示例中,这可能是一个不优雅的解决方案,但通常情况下,if命令在任何语言中都是一个紧张的工具,批处置惩罚也不例外。在下一篇文章中,我们将详细讨论if——由于这是批处置惩罚的一种特性。
本文由博客一文多发平台 OpenWrite 发布!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

饭宝

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表