需要一些帮助使用"如果"批量生成变量和字符串

时间:2017-10-10 21:28:32

标签: batch-file if-statement

我使用For / f循环来读取存储在文件中的值(内容位于我原始帖子的底部)并将参数存储到使用count + 1动态生成的变量,这样可以使用的参数数量是开放式的(因为预期用途是将共享安装到驱动器盘符,可能有任意数量的驱动器,因此可能有参数)。

所使用的所有参数必须匹配并由脚本识别,并且每个参数都具有关联的设置。这方面的一个例子是我在文件中定义的第一个参数是(模式),其设置是(LAN)。 For / f循环(其中两个)的编写方式以及编写配置文件的方式将使用var!count将所有使用的参数分配给(var#)编号!在运行中,相关的设置将分配给(avar#)。

然而,由于参数可以按任何顺序列出,唯一的要求是相关设置在同一行上,在其分隔符号之后,附加到var / avar的数字仅用于确保所有内容都存储在唯一中变量

然后我尝试使用"如果"将存储在循环正在处理的var#中的参数与对项目有用的已知值匹配,例如

var1 = Mode    avar1=LAN        as set by the For /f loop

if var!count!==Mode ( SET Mode=avar!count! )

有希望匹配var1的参数Mode存储在里面,所以Mode变量应设置为avar1(Lan)中存储的任何内容(var1与avar1相同,var2与avar2相同,依此类推等等) )

问题是if语句永远不会评估为true。下面是一个简化的代码示例,我甚至为了测试的目的,手动将var1设置在顶部附近,即使这应该由For / F循环完成并且它仍然没有评估为真

setlocal EnableDelayedExpansion
@echo off
SET count=1
FOR /f "eol=; skip=18 tokens=2 delims=#@" %%x  in (C:\OConf.ini) DO (
SET var!count!=%%x
SET /a count=!count!+1
echo value 1 is %%x  
)

SET count=1
FOR /f "eol=; skip=18 tokens=2 delims=@" %%x  in (C:\OConf.ini) DO (
SET avar!count!=%%x
SET /a count=!count!+1
echo value 2 is %%x  
) 


SET var1 == Mode 

:SetCounters
SET /a count=1 
:SetVars
echo test var!count! 

IF NOT DEFINED var!count! ( GOTO CleanOne )
if var!count! == Mode  ( Echo If this is seen then the "if" evaluated as true )
Echo The value of var1 equals  ( %var1% )
goto EOF

:CleanOne
Echo If you see this then var!count! is null

:EOF
Echo EOF2

对于那些提到有关EOF的人,我认为它在没有标签的情况下作为功能的结束,但至少有一次我运行它,它似乎没有工作(虽然它可能是IF语句失败不合时宜(已经发生过几次))

=============================================== ============

下面更复杂的原帖,根据一些建议,我简化并澄清了我的问题,已经编辑到上面。

=============================================== ============

我正在通过winbuilder创建一个Windows 10 PE解决方案,最终我希望它可以从至少3种方法中使用(直接来自闪存驱动器/ DVD,通过名为easy2boot的实用程序进行多重启动,以及PXE启动来自网络)。然而,我实现的大部分功能都需要一些额外的文件才能在驱动器号Y:上访问,但是根据你的启动方式,这可能意味着安装图像文件,安装网络共享,或只是读取你启动的闪存驱动器或DVD从

因此我正在编写一个在shell启动时加载之前运行的脚本。它做的第一件事就是检查每个驱动器的根目录以查找配置文件,如果可用,它可以进入城镇,如果不可用,则会提示用户回答一些问题并从那里开始。

我一直在写我要称之为的简单脚本'多年来,这是他们如何运行的静态和线性,这是我第一次真正尝试我将称之为“动态脚本”#39;它具有模块化子程序和循环,所有路径都是相对的,或者是用户提示但不是硬编码的。

我为其编写的主要脚本非常适合自己和现在大部分完成的LAN子例程,并且很好地回显了E2B和Flash子例程的占位符文本。

我目前正在研究检查配置文件的子例程,并运行该用户输入。我觉得一切都进入脚本顶空忘记测试了一段时间......

...当我做测试时,我发现" IF"我正在使用的语句永远不会评估为true,即使我手动设置变量并知道它是匹配的。我已经尝试了所有我能用引号思考的排列,没有,百分比和感叹号,空格,没有空格和不同的放置可能性......谷歌搜索和谷歌搜索和我在这里发现的一篇文章似乎应该有效但我没有尝试过从它起作用,但它激励我在这里问!

以下是为了简化开发而硬编码,以便在我的驱动器的根目录中查找配置文件,我计划将其放入的主脚本有一个"如果存在"循环遍历所有驱动器号以在任何驱动器上找到它。此外,我对此脚本发表了评论,不仅解释了什么做了什么,而且还说明了我遇到麻烦的地方。我还评论了一些重复的事情,这些是我实验的结果。现在的脚本将读取预期值并将它们分配给递增的变量并回显它们以显示其工作,但是当它尝试确定已读取的内容并将它们分配给要在其中使用的适当变量时失败让事情发生

setlocal EnableDelayedExpansion
@echo off
::sets the primary counter for the "For" Loop
SET count=1
:: FOR loop to set varibles for the descriptive name of the setting to be 
adjusted for use in
:: determining what the setting value is to adjust
FOR /f "eol=; skip=18 tokens=2 delims=#@" %%x  in (C:\OConf.ini) DO (
SET var!count!=%%x
SET /a count=!count!+1
echo value 1 is %%x  
)
::sets the primary counter for the "For" Loop
SET count=1
::FOR loop to determine the setting values that go with each descriptive Name
FOR /f "eol=; skip=18 tokens=2 delims=@" %%x  in (C:\OConf.ini) DO (
SET avar!count!=%%x
SET /a count=!count!+1
echo value 2 is %%x  
) 

:MyLabel 

::diagnostic code to reference what value is being stored
echo  this is var1: %var1%
echo  this is avar1: %avar1%
echo  this is var2: %var2%
echo  this is avar2: %avar2%
echo  this is var3: %var3%
echo  this is avar3: %avar3%
echo  this is var4: %var4%
echo  this is avar4: %avar4%
echo  this is var5: %var5%
echo  this is avar5: %avar5%
echo  this is var6: %var6%
echo  this is avar6: %avar6%
echo  this is var7: %var7%
echo  this is avar7: %avar7%
echo  this is var8: %var8%
echo  this is avar8: %avar8%
echo  this is var9: %var9%
echo  this is avar9: %avar9%
echo  this is var10: %var10%
echo  this is avar10: %avar10%
echo  this is var11: %var11%
echo  this is avar11: %avar11%
echo  this is var12: %var12%
echo  this is avar12: %avar12%

::echo  this is avar1: %avar1%
::echo  this is avar2: %avar2%
::echo  this is avar3: %avar3%
::echo  this is avar4: %avar4%
::echo  this is avar5: %avar5%
::echo  this is avar6: %avar6%
::echo  this is avar7: %avar7%
::echo  this is avar8: %avar8%
::echo  this is avar9: %avar9%
::echo  this is avar10: %avar10%
::echo  this is avar11: %avar11%
::echo  this is avar12: %avar12%

::in my sample script I am testing against var/avar is known to be null this is test code
echo  this is avar13: %avar13% test
::this code is to show me what part of the script has or has not executed
echo this is not final



:SetCounters
::Set primary counter for script advancement
SET /a count=1 
::Set drive letter counter so it can be compared to the share counter
SET /a D=1    
::Set network share counter so it can be compared to the drive letter counter
SET /a S=1    
:SetVars
::Subrotine to fill in variables for use in the up coming action subrutines
::Diagnostic line added when things were not working right
echo test var!count! D is %D% S is %S%

::escape subrutine so when all values have been filled in, this loop ends and goes to use
IF NOT DEFINED var!count! ( GOTO CleanOne )

:: This is the heavy lifting of this subrutine (also currently non functional for unknown reasons)
:: If bank compares the value of var# (where # is a counter set number) to known valid values, when
:: the valid value is found to match, its associated setting held in avar# is to the batch varible
:: of the same name. Commented out code is either non functional or untest but a new approach concocted
:: before testing, but the need to return to it may come up  so not removed. denoted as not part of
:: this description by adding a preceeding astrik 
:: ========================================================================================

:: Mode is the first test & despite everything I have tried will not evaluate to true
:: tried multiple iterations of including quotes (or not), exclamations and percents symbols
:: around the varibles different ways "var!count!" var!count! %var%!count! 
%var!count!% !var!!count! !var!count!!
:: and a bunch of others, similar iterations around mode, tried spaces and no spaces next to the equal symbols
:: also tried reversing the order of the comparison... *******HELP*******
::*if "%var%!count!" == "Mode" ( Set Mode=avar2 echo test mode %Mode% )
:: Next line is bastardized to simply see when the expression evaluates to true
:: if Mode == !var!!count!  ( Echo Equal )
:: next commented out command is supposed to remove quotes if present to prevent issues, will return to this
:: concept once the issue with the IF statements is dealt with
::*SET Mode=%avar!count!:"=% 
:: also a diagnostic command 
::*echo test mode %Mode%



::=======================================================
:: lines between here and the next divider for me have been temporarily cut to another file  to reduce clutter
:: and save my sanity while I takle the problem. pasted back to demonstraight intended functionality.

:: Mode has 3 valid options currently, Flash/DVD, LAN, E2B and will be used to either mount a image file on a E2B
:: drive to a drive letter, or to mount (possibly multiple) network shares to drive letters
if var!count!==Mode ( SET Mode=avar!count! )
::if var!count!==Mode ( SET Mode=%avar!count!:"=% )

:: Perf is short for performance and is to determine if the install driver packs subroutine should run to increase performance
:: and or recognize otherwise unknown devices, declining this uses only baked in drivers. Valid options are Yes/No
if var!count!==Perf ( Set Perf=avar!count!)
::if var!count!==Perf ( SET Perf=%avar!count!:"=% )

:: ImgPth is for the image path to be mounted to the Y:, currently it is only intended that 1 image be mounted however
:: as I write this I realize the way I am approaching mounting network shares could allow multiple images to be added also
if var!count!==ImgPth ( Set ImgPth=avar!count!)
::if var!count!==ImgPth ( SET ImgPth=%avar!count!:"=% )

:: NumDrv is supposed to be how many network shares were to be mounted so the script could allocate enough varibles
:: I have sense adopted a new approach that can auto-detect and just run, haven't removed yet
if var!count!==NumDrv ( Set NumDrv=avar!count!)
::if var!count!==NumDrv ( SET NumDrv=%avar!count!:"=% )

:: Server is used to name the server that has the network share on it that will get mounted to a drive letter
:: the tools used only support one server connection via one user name, so this can only be set once.
:: eg \\server01\something\share would translate to server01  (no need for slashes)
if var!count!==Server ( Set Server=avar!count!)
::if var!count!==Server ( SET Server=%avar!count!:"=% )

:: Usr is the user name to authenticate with the server to access the network share
:: the tools used only support one server connection via one user name, so this can only be set once.
if var!count!==Usr ( Set Usr=avar!count!)
::if var!count!==Usr ( SET Usr=%avar!count!:"=% )

::Pass is the password to use in authenticating with the server
:: the tools used only support one server connection via one user name, so this can only be set once.
if var!count!==Pass ( Set Pass=avar!count!)
::if var!count!==Pass ( SET Pass=%avar!count!:"=% )

::DrvLtr denotes what drive letter you want the network share mounted to. X: will already be in use by the system
:: if using on a computer with windows installed on local HDD then C: will be in use. If newer windows with recovery
:: partitions and or otherwise multiple drives/partitions D: E: will also likely be in use. Y: is a special case and 
:: ultimatly the point of this entire script. Core files to boot and opperate are loaded to the X: ram disk, however 
:: to save RAM and increase compatibility additional functionality that requires additional files not stored in the 
:: ramdisk need to be mounted to Y: and Y: is reserved for this use only. So do not use C: D: E: X: (Y: unless its for 
:: the specified files)
if var!count!==DrvLtr ( 
Set DrvLtr!DL!=avar!count!
::Set DrvLtr!DL!=%avar!count!:"=%
::Next bit was intended to be a diagnostic message, alas the test never got that far
Echo DrvLtr Subroutine has run for the !DL! time and stored %DrvLtr%!DL! for use 
:: the counter being modified below allows for it to be determined how many times this subroutine has run
:: by the time this loop exits it should match the number of times the Share routine has run, if it doesn't
:: then there is an error, but by taking the smaller number and running the mount share command only the 
:: lessar times it can be assured each share has a drive letter and vice versa
SET /a DL=!DL!+1
)
:: path to the network Share, multiple of these can be mounted to different drive letters
:: eg \\server01\something\share would translate to something\share, or if the share isnt in a sub folder
:: eg \\server01\share then it would translate to just    share   (slashes only used if more then one folder deep)
if var!count!==Share ( 
Set Share!SH!=avar!count!
::Set DrvLtr!SH!=%avar!count!:"=%
Echo DrvLtr Subrutine has run for the !SH! time and stored %DrvLtr%!SH! for use
:: the counter being modified below allows for it to be determined how many times this subroutine has run
:: by the time this loop exits it should match the number of times the Share routine has run, if it doesn't
:: then there is an error, but by taking the smaller number and running the mount share command only the 
:: lessar times it can be assured each share has a drive letter and vice versa
SET /a SH=!SH!+1
)
:: advances the main counter so the next pass through the loop doesn't use the same variable and thus the same information 
SET /a count=!count!+1 
:: its commented out for troubleshooting but this goto is to repeat the loop
::goto :SetVars
pause
:: the above if statements currently are nonfunctional, the below is my first draft at takling the idea of mounting multiple network shares
:: before realizing the approach had some limitations in how drive letters and their respective shares could be listed in the config file
:: originally intended that the config file would list either the letter then the share, next letter next share, or possibly share then letter
:: this code was then tweaked so the config file could accept letter, share, share, letter, letter, share; however having more then two letters 
:: and or shares in sequence would conceptially (I never tested this code) break the code, and a bathroom break brainstorm would clue me into 
:: much simpler code that shouldnt care how the drive letters and shares are listed as long as there are equal numbers of them, and if theres not
:: a still useable fail can be acheved by using the lower number of how many shares listed vs drive letters 

REM attempting  subroutine rewrite to be completly agnostic to drive verses share ordering, commented out subroutine in case
REM I fail and or I need to use parts of this
REM #(if sh) commented out as more versitile and similar functionality provided by adding another counter advance near the end
REM #this should allow the drive letters or shares to be listed back to back and still be set as long as its still grouped to 
REM #one side or the other with its other value (S= share D= Drive: DSDSDS was the original plan, DSSDDS or SDDSSD would be prevented
REM #by this method but would work with the counter advance)
::if var!count!==DrvLtr (                                                     
REM Checking for drive letter option
::if SH==0 (            REM checking if share has already been set this plus next option prevents a required order of things, though the options must be set together
::Set DrvLtr=avar!count!                       REM Sets the Drive Letter value 
::SET /a count=!count!+1                     REM If share hasnt been set, advances the counter so the share can be set
::if var!count!==Share ( Set Share=avar!count!        REM sets the share
::Set /p DL=1              REM notates that the share has been set so the next subroutine wont muck things up trying to do the same thing
::echo DrvLtr Subrutine has run varibles are %DrvLtr% and %Share%    REM Diagnostic message to know if this subrutine ran and if so did it set correctly
::SET /a count=!count!+1        REM advances the counter so presumably the share subrutine wont run as it was set here
::)
::else ( Echo Share set errored )
::)
:CleanOne

:: makes sure the number of drive letters requested matches the number of shares being mounted or if not uses the lesser number
Set /a Dnum=!DL!
set /a Snum=!SH!
If %Dnum% LEQ %Snum% set /a RC=%Dnum%
If %Snum% LEQ %Dnum% set /a RC=%Snum%
goto :CleanTwo

:CleanTwo
REM to modify later, currently echoing to test current script operation
:: this is when I decided to test and discovered the broken IF statements
:: this subroutine was conceptualized and removing all quotes that maybe stored in variables, however before writing something to do that
:: I found sample code that could do that on the fly and wrote it into the if statements, sense being commented out as I tackle why the IF's are broken
Echo Mode equals %Mode%
Echo Perf equals %Perf%
Echo NumDrv equals %NumDrv%
Echo Server equals %Server%
Echo Usr equals %Usr%
Echo Pass equals %Pass%
Echo DrvLtr equals %DrvLtr%
Echo Share equals %Share%
Echo DrvLtr2 equals %DrvLtr2%
Echo Share2 equals %Share2%
Echo DrvLtr3 equals %DrvLtr3%
Echo Share3 equals %Share3%

:: after making sure nothing is muddled with quotes, and maybe slashes, and likely inserting some code above the SetVars rutine to set all to either upper/lower 
:: case to prevent issue, the assigned variables will be used. 

:: Flash/dvd will simply ask for the performance option and look for a DriverPacks and install them 
:: if performance mode is desired. 

:: E2B, is for use with Easy2Boot using a .imgptn file which gets mapped to the MBR of the flash drive (it's a compatibility hack for uefi)
:: easy2boot supports other image files but the functionality of automatically unmounting, and remapping to a drive letter are automatically done with baked in options, 
:: plus access to the E2B drive proper is never lost, with .imgptn being mapped to the drive via the MBR all access to the main drive is lost until you run a script 
:: provided the developer to restore the MBR to its original state. E2B mode in this script is intended to call that script (well a bastardized version that doesnt need
:: user input, via loops and auto detection (upcoming, my previous version I tweaked for my PE3 build years ago, was hard coded for set options that were true about 90% time,
:: everything about this project as opposed to my old project is to be modular, relative, and dynamic so hard coding things esp things that dont work all the time are an antithesis)
:: Once the script is run to restore the original MBR and primary drive access is restored, the image "path\file" stored in ImgPth will be mounted to the Y: using imdisk.

:: Lan is intended for PXE boot situations and will mount a network share that contains the files needed for Y:  to that drive letter, and additionally any extra shares indicated

:: performance mode will then run or not as specified, followed by starting the shell




:MyLabel 
:: Original placment of this diagnostic readout, some iterations of the broken IF statements prevented the script from completing 
:: and this was never seen, and in takling this problem I needed to see if these were set so copied above

echo  this is var1: %var1%
echo  this is avar1: %avar1%
echo  this is var2: %var2%
echo  this is avar2: %avar2%
echo  this is var3: %var3%
echo  this is avar3: %avar3%
echo  this is var4: %var4%
echo  this is avar4: %avar4%
echo  this is var5: %var5%
echo  this is avar5: %avar5%
echo  this is var6: %var6%
echo  this is avar6: %avar6%
echo  this is var7: %var7%
echo  this is avar7: %avar7%
echo  this is var8: %var8%
echo  this is avar8: %avar8%
echo  this is var9: %var9%
echo  this is avar9: %avar9%
echo  this is var10: %var10%
echo  this is avar10: %avar10%
echo  this is var11: %var11%
echo  this is avar11: %avar11%
echo  this is var12: %var12%
echo  this is avar12: %avar12%

::echo  this is avar1: %avar1%
::echo  this is avar2: %avar2%
::echo  this is avar3: %avar3%
::echo  this is avar4: %avar4%
::echo  this is avar5: %avar5%
::echo  this is avar6: %avar6%
::echo  this is avar7: %avar7%
::echo  this is avar8: %avar8%
::echo  this is avar9: %avar9%
::echo  this is avar10: %avar10%
::echo  this is avar11: %avar11%
::echo  this is avar12: %avar12%

echo  this is avar13: %avar13% test
echo this is not final
goto test2

:Final
Echo this is final

:EOF

echo done 




pause
:: a command I refrenced, from something I used a while back

::SET count=1
::FOR /F "tokens=* USEBACKQ" %%F IN (`Net User %Username%`) DO (
::  SET var!count!=%%F
::  SET /a count=!count!+1
::  SET Shell=Chrome
)





::========================================================
:: Also these are diagnostic commands and subroutines that may share names with some of the above that was
:: temporarily cut out as I takle the problem.
:: Echo %var1% is still var1 right
:: goto EOF

:: :CleanOne
:: Echo CleanOne 13

:: :EOF
:: Echo EOF2


:: commented these out

另外作为参考,我一直在测试的示例配置文件如下:

//Mode Declares how the system should mount additional required files, based on how the system was booted
//
//Performance mode Loads drivers either from the Y: or from the E2B flash drive, depending on Mode.
//Performance mode may take plus or minus 5 minutes to fully load, and installs all relevant drivers found in the 
//DriverPacks folder in Y: (on Flash/LAN) or on the E2B drive (E2B), For your wait time you get proper performance
//From all your devices, and or visibility if not otherwise recognized, as long as the drivers are in the folder.
//
//Network drive specifies the Server, Share, Login Credentials and the desired Drive letter to mount the share too.
//Y: is reserved for Files required by the Diagnostic Enviornment, LAN requires the first loaded share to contain 
//Non-Wim files found in the .iso. Flash/E2B can also mount Network shares but Y: must not be used.
//
//No Slashes are required when entering the network parameters, unless your username requires a domain prefix
//you may only connect to one server, and only use one user to login, however shares are only limited by available 
//Drive letters. X: Y: are reserved by the environment, if the computer used has a HDD with windows on it C: will be 
//used, if modern windows then there will be additional partitions loaded if they are not hidden. 
//Advise not to use B:C:D:E:X:Y:

//==========================================================================
;//(Mode can be: Flash/E2B/LAN)
!#Mode @ LAN
;//(Performance Mode can be: Yes/No)
!#Perf @ No   
;//(Network Drive Parameters)  
;//(Number of network Shares to mount including Y: if LAN booting)
!#NumDrv @ 3    
;//(Server to connect to on LAN)
!#Server @ oc3-omega01    
;//(User name to authenticate with the server)
!#Usr @ SomeName    
;//(Password to authenticate with the Server)
!#Pass @ SomePassword    
;//(Drive letter to assign the first share)
!#DrvLtr @ Y     
;//(Share on server to map to drive)
!#Share @ OmegaDR     
;//(Repeat DrvLtr and Share lines for as many shares as you are mapping, Do not reuse drive letters)
!#DrvLtr @ Z     
!#Share @ Data     
!#DrvLtr @ U     
!#Share @ "Manual Backups"      

我应该说没有什么可以保密的,所以它可以共享,就像我完成时一样,是的,它符合我的目标://一个//可以动态配置多个用途的图像,但我也计划分享它,以便其他人与winpe项目可以受益。

这个项目实际上是各种类型的更新,因为我有一套功能齐全的PE3(基于win7的)工具集,但我发现它很难在UEFI系统上看不到GUID驱动器。我的PE3图像中使用的脚本也是静态的,虽然它们大部分时间都在工作,但每次都不会,因为我在脚本中输入的任何内容都不能与任何随机的新机器匹配。这次我试图制作一个通用的启动脚本。

1 个答案:

答案 0 :(得分:0)

if var!count!==Share (

将被解析为

if var1==Share (

假设count的值为1

IF非常字面 - 比较运算符两侧的两个字符串按字面比较,因此指令为"如果字符串 var1等于文字字符串分享"

您需要 var1内容,即!var%count%!这是 - 两个阶段 - 首先用内容{{1}替换任何%count%然后检索结果的内容。

这就是为什么count不应该用于一般!var!的情况,而是保留在需要这个两阶段解析的地方以及在循环中改变所需变量的时候。< / p>

BTW - value of a variable有一个if开关,可以使比较不区分大小写。

/i将列出所有变量,从set var

开始

var预先定义为&#34;文件结尾&#34;。 :EOF预定义为&#34;转到文件结尾&#34; (即退出当前例程)如果您定义自己的标签goto :eof,则可能会遇到问题 - 例如,:eof很乐意到达您的标签,但goto eof将退出例程(我不能使用goto :eof语法的另一个原因)