在批处理参数数组

时间:2016-07-10 12:51:52

标签: batch-file filter cmd

我正在编写批处理,用户必须输入要作为批处理参数激活的设备列表。该列表可以包含随机顺序的设备号和/或名称以及可能的重复和残留物(即,不存在或不存在就绪设备)。批处理:default 部分以随机顺序存储所有当前就绪设备的数组 dev _#= name 。初始任务是过滤用户输入以排除重复项和残留项,并显示要激活的已排序的准备好的设备号列表。然后激活该列表中的设备。什么样的高效短代码可以完成过滤任务?

@echo off
setlocal EnableDelayedExpansion
:default
set "dev_1=AB" & set "dev_2=BA" & set "dev_3=AC" & set "dev_16=CA" & set "dev_19=BC" & set "dev_6=CB" & set "dev_7=ZA"
set "dev_8=AZ" & set "dev_29=UA" & set "dev_10=YZ" & set "dev_18=YW" & set "dev_12=AK" & set "dev_13=AJ" & set "dev_14=HT"

rem batch arguments entered by user
rem 1 3 6 AB BA YZ 12 17 21 YK AU AK BA BU ZA

rem Desired sorted filtered output
rem 1 2 3 6 7 10 12

3 个答案:

答案 0 :(得分:6)

使用本机批处理命令的一个班轮 - 没办法!

但它并没有占用大量代码,特别是如果你在设计一些数据结构方面具有创造性。请注意,唯一重要的代码是:test例程。其余的是初始化和测试用例。

@echo off
setlocal

:: Clear devices
for /f "delims==" %%A in ('set dev. 2^>nul') do set "%%A="

:: Define devices
for %%A in (
  " 1=AB" " 2=BA" " 3=AC" "16=CA" "19=BC" " 6=CB" " 7=ZA"
  " 8=AZ" "29=UA" "10=YZ" "18=YW" "12=AK" "13=AJ" "14=HI"
) do for /f "tokens=1,2 delims==" %%a in (%%A) do for %%N in (%%a) do (
  set "dev.%%N= %%a"
  set "dev.%%b= %%a"
)

call :test 1 3 6 AB BA YZ 12 17 21 YK AU AK BA BU ZA
call :test sadf asdfa
call :test aj 6 13 CB
exit /b

:test
setlocal EnableDelayedExpansion

:: Clear selected
for /f "delims==" %%A in ('set selected. 2^>nul') do set "%%A="

:loadArgs  Define a variable for each unique device specified in args
if "%~1" neq "" (
  if defined dev.%~1 set "selected.!dev.%~1!=1"
  shift /1
  goto :loadArgs
)

:: Write out the unique values in sorted order
set "dev= "
for /f "tokens=2 delims== " %%A in ('set selected. 2^>nul') do set "dev=!dev!%%A "
echo selected devices = %dev:~1%

exit /b

- 输出 -

selected devices = 1 2 3 6 7 10 12
selected devices =
selected devices = 6 13

如果您确信用户永远不会在参数中包含*?),那么FOR循环可以替换GOTO循环。 :test例程简化为以下内容:

:test
setlocal EnableDelayedExpansion

:: Clear selected
for /f "delims==" %%A in ('set selected. 2^>nul') do set "%%A="

:: Define a variable for each unique device specified in args
for %%A in (%*) do if defined dev.%%~A set "selected.!dev.%%~A!=1"

:: Write out the unique values in sorted order
set "dev= "
for /f "tokens=2 delims== " %%A in ('set selected. 2^>nul') do set "dev=!dev!%%A "
echo selected devices = %dev:~1%

exit /b

现在,如果你愿意超越纯天然批次的范围,那么一个班轮肯定是可行的。我会使用我的JSORT.BATJREPL.BAT实用程序。 JSORT能够对数字进行排序,因此初始化值中不再需要前导空格。

现在:test例程确实是一个单一的例子:

@echo off
setlocal

:: Clear devices
for /f "delims==" %%A in ('set dev. 2^>nul') do set "%%A="

:: Define devices
for %%A in (
  "1=AB" "2=BA" "3=AC" "16=CA" "19=BC" "6=CB" "7=ZA"
  "8=AZ" "29=UA" "10=YZ" "18=YW" "12=AK" "13=AJ" "14=HI"
) do for /f "tokens=1,2 delims== " %%a in (%%A) do (
  set "dev.%%a=%%a"
  set "dev.%%b=%%a"
)

call :test 1 3 6 AB BA YZ 12 17 21 YK AU AK BA BU ZA
call :test sadf asdfa
call :test aj 6 13 CB
exit /b

:test
(for %%A in (. %*) do @call echo(%%dev.%%A%%) | jsort /n /u | jrepl "(\s|%%.*?%%)+" " " /m | jrepl "^ " ""
exit /b

:test
echo(%*|jrepl "(^|\s*)(\S+)" "env('dev.'+$2)" /jmatch | jsort /n /u | jrepl "\s+" " " /m | jrepl "^ " ""
exit /b

答案 1 :(得分:1)

如果您对替代方案持开放态度,请参阅VBScript中的示例(保存在.vbs扩展名而不是.bat的文件中):

input = InputBox("", , "1 3 6 AB BA YZ 12 17 21 YK AU AK BA BU ZA")
values = Split(input)

' Adds the values to a sorted list that matches the case    
Set list = CreateObject( "System.Collections.Sortedlist" )    
For Each value in values
   Select Case value
      Case "1" , "AB" : list(1 ) = 0
      Case "2" , "BA" : list(2 ) = 0
      Case "3" , "AC" : list(3 ) = 0
      Case "6" , "CB" : list(6 ) = 0
      Case "7" , "ZA" : list(7 ) = 0
      Case "8" , "AZ" : list(8 ) = 0
      Case "10", "YZ" : list(10) = 0
      Case "12", "AK" : list(12) = 0
      Case "13", "AJ" : list(13) = 0
      Case "14", "HT" : list(14) = 0
      Case "16", "CA" : list(16) = 0
      Case "18", "YW" : list(18) = 0
      Case "19", "BC" : list(19) = 0
      Case "29", "UA" : list(29) = 0
   End Select
Next

' To show the items in the list   
For i = 0 To list.Count - 1
    output = output & list.GetKey(i) & " "
Next
MsgBox output

另一种选择是PowerShell(扩展名.ps1):

$s = "1 3 6 AB BA YZ 12 17 21 YK AU AK BA BU ZA"
$a = -split $s 

$a = $a -replace "AB", 1
$a = $a -replace "BA", 2
$a = $a -replace "AC", 3
$a = $a -replace "CB", 6
$a = $a -replace "ZA", 7
$a = $a -replace "AZ", 8
$a = $a -replace "YZ", 10
$a = $a -replace "AK", 12
$a = $a -replace "AJ", 13
$a = $a -replace "HT", 14
$a = $a -replace "CA", 16
$a = $a -replace "YW", 18
$a = $a -replace "BC", 19
$a = $a -replace "UA", 29

$a = $a | ? { -split "1 2 3 6 7 8 10 12 13 14 16 18 19 29" -contains $_ }
$l = $a | % { iex $_ }
$l = $l | sort-object -Unique 
$l -join " "

但是运行PowerShell脚本有点挑战性,所以你可以从.bat这样的文件中运行它:

powershell -noprofile -command "&{"^
 "$s = '1 3 6 AB BA YZ 12 17 21 YK AU AK BA BU ZA' ;"^
 "$a = -split $s ;"^
 "$a = $a -replace 'AB', 1  ;"^
 "$a = $a -replace 'BA', 2  ;"^
 "$a = $a -replace 'AC', 3  ;"^
 "$a = $a -replace 'CB', 6  ;"^
 "$a = $a -replace 'ZA', 7  ;"^
 "$a = $a -replace 'AZ', 8  ;"^
 "$a = $a -replace 'YZ', 10 ;"^
 "$a = $a -replace 'AK', 12 ;"^
 "$a = $a -replace 'AJ', 13 ;"^
 "$a = $a -replace 'HT', 14 ;"^
 "$a = $a -replace 'CA', 16 ;"^
 "$a = $a -replace 'YW', 18 ;"^
 "$a = $a -replace 'BC', 19 ;"^
 "$a = $a -replace 'UA', 29 ;"^
 "$a = $a | ? { -split '1 2 3 6 7 8 10 12 13 14 16 18 19 29' -contains $_ } ;"^
 "$l = $a | %% { iex $_ } ;"^
 "$l = $l | sort-object -Unique ;"^
 "$l -join ' ' ;"^
 "}"

pause

答案 2 :(得分:0)

这是一个扩展注释,显示了Dave上面回答中使用的本机Cmd排序的读者的应用程序示例。它需要用零填充编号的变量。

@echo off
setlocal EnableDelayedExpansion
set "devs= 1 10 12 2 3 4 6 7 8 9"
for %%k in (!devs!) do (set /a "devl=100+%%k" & set "devl=!devl:~-2!"
    set "dev.!devl!=!devl!")
for /f "tokens=2 delims==" %%l in ('set dev.') do set "devn=!devn! %%l"
echo !devn!

exit /b

:: output
:: 01 02 03 04 06 07 08 09 10 12