【问题标题】:How do I set and iterate over a matrix如何设置和迭代矩阵
【发布时间】:2017-11-14 08:16:55
【问题描述】:

我想初始化一个矩阵,然后在几个地方迭代它。

这是我迄今为止根据我从其他问题中可以找到的内容,但显然我做错了什么,因为 SERVICES 在回声中为空。

代码

rem SET SERVICES[#][0]="Window Title"
rem SET SERVICES[#][1]="Relative .bat path"

SET SERVICES[0][0]="Hello World!"
SET SERVICES[0][1]="service/hello.bat"
SET SERVICES[1][0]="Hello World! 2"
SET SERVICES[1][1]="service/hello 2.bat"

for %%s in (%SERVICES%) do call ServiceStarter.bat %%s[0] %%s[1]

for %%s in (%SERVICES%) do call ServiceStopper.bat %%s[0]

输出

C:\securboration>SET SERVICES[0][0]="Hello World!"

C:\securboration>SET SERVICES[0][1]="service/hello.bat"

C:\securboration>SET SERVICES[1][0]="Hello World! 2"

C:\securboration>SET SERVICES[1][1]="service/hello 2.bat"

C:\securboration>for %s in ((null)) do call ServiceStarter.bat %s[0] %s[1]

C:\securboration>for %s in ((null)) do call ServiceStopper.bat %s[0]

预期

它应该遍历外部数组,以便我可以将子数组的元素作为参数传递给其他 .bat 文件。

那么矩阵初始化有什么问题,一旦设置好,我如何迭代该矩阵以将值传递给其他调用?

这可能之前已经回答过,但我认为其他答案假设的知识水平比我的知识水平高,所以你能以不需要工作批处理文件知识的方式解释吗?此外,支持空间也很重要。

【问题讨论】:

标签: windows loops batch-file matrix


【解决方案1】:
<!-- language: lang-dos -->

@ECHO OFF
SETLOCAL
rem SET SERVICES[#][0]="Window Title"
rem SET SERVICES[#][1]="Relative .bat path"

SET SERVICES[0][0]="Hello World!"
SET SERVICES[0][1]="service/hello.bat"
SET SERVICES[1][0]="Hello World! 2"
SET SERVICES[1][1]="service/hello 2.bat"

for /f "tokens=2,3*delims=[]=" %%a in ('set SERVICES[') do IF %%b==0 CALL call q44506472_s.bat %%services[%%a][0]%% %%services[%%a][1]%%
for /f "tokens=2,3*delims=[]=" %%a in ('set SERVICES[') do IF %%b==0 CALL call q44506472_s.bat %%c %%services[%%a][1]%%


GOTO :EOF

其中 q44506472_s.bat 是一个虚拟演示文件,包含

@ECHO OFF
SETLOCAL
ECHO parameter1=%1
ECHO parameter2=%2
ECHO ----------------

(只是为了显示正在传输的参数)

所以 - 象形文字是这样做的:

执行set services[ 命令,列出所有以services[ 开头的变量,格式为services[0][1]=somestring

for /f 标记了set 生成的每一行,使用三个字符[]= 作为分隔符。所以,使用services[0][1]=somestring,我们得到

services 作为令牌1 - 未分配
0 作为令牌2 - 分配给%%a 作为2 是第一个token 号码指定
1 作为令牌3 - 分配给%%b因为3 是下一个token 提名号码
somestring 作为令牌*(最高提名令牌之后的剩余部分)-分配给%%c

标记由任何选定分隔符的任何序列分隔。

所以,选择%%b==0 将选择第二个数组维度 = 0,然后我们通过calling 执行call,例如%%services[%%a][0]%%,它被解析为服务的内容[0][0]。由于此时%%a 是一个活动元变量,它首先被替换,然后解析器将剩余的%% 解析为%% 转义%)。

第一个 call 执行解析派对技巧;第二个执行实际的子程序并解析参数。

由于%%c 无偿包含第一个参数所需的内容,如果您愿意,也可以使用它。


从那里你的发展 - 好吧,cmd 并不是最聪明的 - 我认为你有点太聪明了。有两个问题 - 第一个是 windowtitle... 被引用,造成严重破坏,第二个是您将“引用字符串”作为变量值。就个人而言,我会根据需要应用引号,并使用 cmd 特征语法 SET "var=value"(其中值可能为空),用于确保分配的值中不包含任何杂散的尾随空格。

我会改变

 for /f "tokens=2,3*delims=[]=" %%a in ('set SERVICES[') do IF %%b==0 CALL for /f "Delims=:" %%A in ('tasklist /v /fi "WINDOWTITLE eq %%services[%%a][0]%%"') do if %%A==INFO SET errorinfo=1

(请注意,cmd 对直接在 for/f 命令中的单引号之前/之后的换行符非常满意 - 只是让这些行更易于编辑......)

for /f "tokens=2,3*delims=[]=" %%a in ('set SERVICES['
 ) do IF %%b==0 CALL :seterrorinfo %%services[%%a][0]%%

ECHO errorinfo="%errorinfo%"

GOTO :EOF

:seterrorinfo
for /f "Delims=:" %%A in ('tasklist /v /fi "WINDOWTITLE eq %~1"') do ECHO ***%%A***&if %%A==INFO SET errorinfo=1

GOTO :eof

:seterrorinfo 现在是一个子例程,由数组中的引用值作为参数提供。

在子例程中,%~1 被第一个参数的值替换,~ 运算符删除所有封闭引号。

我不会评论INFO 的检测是否合适(但我建议在例程开始时清除errorinfo。考虑如果多次调用例程会发生什么 -如果%%A 在下一次调用中不是INFO,则上一次调用的值将保留在errorinfo 中。)为了便于分析,我将echo %%A 留在了子例程中。

请注意,如果您在 SO 上阅读了一些关于 delayed expansion 的文章,您也许可以使用它来避免 call set 混乱。您的原始数据包含!,所以我避免使用它,因为! 然后变成了一个特殊字符。

【讨论】:

  • 非常感谢!我现在正在尝试使用它来确认使用for /f "tokens=2,3*delims=[]=" %%a in ('set SERVICES[') do IF %%b==0 CALL for /f "Delims=:" %%A in ('tasklist /v /fi "WINDOWTITLE eq %%services[%%a][0]%%"') do if %%A==INFO SET errorinfo=1 打开的所有窗口(启动时没有崩溃);但是是说IF 0 == 0 CALL for /f "Delims=:" %A in ('tasklist /v /fi "WINDOWTITLE eq %services[4][0]%"') do if %A==INFO SET errorinfo=1 services[4][0]A was unexpected at this time.我在这里做错了什么?
  • 非常感谢您的黑魔法专业知识。 ^^ 脚本现在可以运行了。
【解决方案2】:

这仍然可以以更简单的方式完成,使用最基本的 for 循环。 关键在于迭代变量名的正确部分以减少扩展它所需的代码。

在这种情况下,可用的服务索引及其分隔符。

@echo off
    Set Services="0][0" "0][1" "1][0" "1][1"
    Set SERVICES[0][0]="Hello World!"
    Set SERVICES[0][1]="service/hello.bat"
    Set SERVICES[1][0]="Hello World! 2"
    Set SERVICES[1][1]="service/hello 2.bat"

For %%A in (%Services%) do (
    CALL echo(%%Services[%%~A]%%
    Choice /N /C NY /M "Start Service? NY"
    If Errorlevel 2 Call :service %%Services[%%~A]%%
)
    pause
    Exit /B
:service
    Echo( Service Selected: %1
    pause
Exit /B

此外,您可以将每个索引分配给特定的命令以执行操作:

@echo off
    Set Services="0][0" "0][1" "1][0" "1][1"
    Set "0][0=Echo(A command or Parameter for service 0 0"
    Set "0][1=Echo(A command or Parameter for service 0 1"
    Set "1][0=Echo(A command or Parameter for service 1 0"
    Set "1][1=Echo(A command or Parameter for service 1 1"
    SET SERVICES[0][0]="Hello World!"
    SET SERVICES[0][1]="service/hello.bat"
    SET SERVICES[1][0]="Hello World! 2"
    SET SERVICES[1][1]="service/hello 2.bat"

    Setlocal EnableDelayedExpansion
For %%A in (%Services%) do (
    echo(!Services[%%~A]!
    Choice /N /C NY /M "Start Service? NY"
    If Errorlevel 2 Call :service "!%%~A!" "!Services[%%~A]!"
)
pause
Exit /B
:service
%~1 !%~2!
pause
Exit /B

【讨论】:

    猜你喜欢
    • 2016-07-27
    • 1970-01-01
    • 1970-01-01
    • 2016-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-30
    相关资源
    最近更新 更多