Batch file 筛选批处理参数数组中的重复项

Batch file 筛选批处理参数数组中的重复项,batch-file,filter,cmd,Batch File,Filter,Cmd,我正在编写一个批处理,其中用户必须输入一个要激活的设备列表作为批处理参数。该列表可能包含随机顺序的设备编号和/或名称,以及可能的重复项和无效项,即不存在或未准备好的设备。batch:default部分以随机顺序存储所有当前就绪设备的数组dev=名称。最初的任务是过滤用户输入,以排除重复项和无效项,并提供一个已排序的就绪设备编号列表以激活。然后激活该列表中的设备。什么高效的短代码可以完成过滤任务 @echo off setlocal EnableDelayedExpansion :default

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

@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

带有本机批处理命令的一行程序-不可能

但是它不需要太多的代码,特别是如果您在设计一些数据结构方面有创造性的话。请注意,唯一计数的代码是: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
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能够对数字进行排序,因此初始化值中不再需要前导空格

现在:测试例程实际上是一个单行程序:

@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


如果您对备选方案持开放态度,下面是“保存在扩展名为.vbs而不是.bat的文件中”中的一个示例:

另一种选择是PowerShell扩展。ps1:

但是运行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

这是一个扩展注释,为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

如果这与前面的问题有关,那么批处理文件就太复杂了。要么重新思考你在做什么,要么编写一个程序。您正在尝试执行批处理文件并非真正设计用于执行的操作。虽然这与我之前的任何问题都不相关,但我希望您能参考任何MS源,其中定义了批处理文件的设计用途,并建议使用何种工具更适合此任务。我知道有些人可以在真正的艺术水平上编写批处理任务。谢谢Dave。“转到”部分中可能有输入错误,但由于某些原因,它不会在我的系统上显示错误:“已选择”。!开发人员%~1=1?@sambul35-是的,你是对的。我修正了密码。正如您所看到的,结束报价不是必需的,但不包括它是不好的形式。如果没有右引号,则行上的任何尾随空格都将包含在指定的值中。对于结束引号,所有剩余的字符都被忽略。奇怪的是,当我错过结束双引号时,代码总是给出一个错误。但是你的代码即使在这种输入错误下也能工作。这是为什么?@sambul35-没有简单的答案。这完全取决于上下文。一般经验法则-除非有特殊原因,否则始终提供结束引号。是否有方法防止在“set-dev”中自动排序变量?在某些情况下,如将其值从0更改为作为批处理参数提供的值,这是可取的。
$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 -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
@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