批处理文件:列出目录&文件名称为单个变量并显示为选择菜单

时间:2013-11-18 13:15:14

标签: windows shell variables batch-file cmd

我在许多不同的Windows机器上使用RDP,有时必须将RDP合并为一个,然后将rdp从那里转移到另一个。

我想知道是否可以创建一个可以读取设置路径中所有目录的名称的批处理文件,然后将它们显示为编号变量,如菜单。 输入我的选择后,它将对所选目录中的所有.rdp文件执行相同的操作。

下面是一个如何为每个文件手动硬​​编码的示例...但是我需要适应将新的rdp文件放入目录而不必每次在批处理文件中手动添加它的东西,因为网站/个人电脑和名称的数量可以定期更改。

:site
ECHO Location List
ECHO.
ECHO 1 NSW
ECHO 2 QLD
ECHO.
SET /p site=Enter Selection: 
IF "%site%"=="1" GOTO NSW
IF "%site%"=="2" GOTO QLD    

:NSW
SET dirname=C:\Machine\NSW\
ECHO Machine List
ECHO.
ECHO 1 Client01.rpd
ECHO 2 Server01.rpd
ECHO 3 Server02.rdp
ECHO.
SET /p machine0=Enter Selection: 
IF "%machine0%"=="1" SET machine1=%dirname%Client01.rdp
IF "%machine0%"=="2" SET machine1=%dirname%Server01.rdp
IF "%machine0%"=="3" SET machine1=%dirname%Server02.rdp
GOTO connection

:connection
mstsc %machine1% /console

我发现了几个与此类似的问题(例如herehere),但它们似乎只是显示一个列表,而不是将它们放入菜单中的选项,我也是仍然不完全了解FOR命令的工作原理。

目录结构示例。

C:\Batchfile.bat
C:\Machines\NSW\Client01.rdp
C:\Machines\NSW\Server01.rdp
C:\Machines\NSW\Server02.rdp
C:\Machines\QLD\Client01.rdp
C:\Machines\QLD\Client02.rdp
C:\Machines\QLD\Server01.rdp

基本目录将设置为C:\ Machines然后批处理将每个子目录名称存储到编号变量并将它们回显到屏幕并提示选择。

Location List

1 NSW
2 QLD

Enter Selection:_

如果用户输入1然后它会将QLD子目录中的每个.RDP文件名存储到编号变量并将它们回显到屏幕并提示选择。

Machine List for NSW

1 Client01.rpd
2 Server01.rpd
3 Server02.rdp

Enter Selection:_

此时用户进行选择后,我想使用选定的.rdp文件和mstsc命令启动到所选计算机的rdp会话,然后循环开始以允许在同一时间打开第二个连接时间。

我很感激你能给予的任何帮助。

2 个答案:

答案 0 :(得分:2)

这是一种方式:

@echo off
setlocal enabledelayedexpansion

:Start
ECHO Location List
ECHO.
ECHO NSW
ECHO QLD
ECHO.
SET /p site=Enter Selection: 

for /f %%a in ('dir /b/s "c:\Temp\%site%\*.rdp"') do (
  set /a i+=1
  echo !i! - %%~nxa
  set mach[!i!]=%%~nxa
)
set /p m0=Enter Selection: 
echo mstsc !mach[%m0%]! /console
set /p sel=Would you like to launch another [y/n]? 
if /i "%sel%" EQU "y" Goto :start

@echo off
setlocal enabledelayedexpansion

:Start 
ECHO Location List
ECHO.
ECHO 1 - NSW
ECHO 2 - QLD
ECHO.
SET /p site=Enter Selection: 

set i=0 & set a=0
set site[1]=NSW
set site[2]=QLD

for /f %%a in ('dir /b/s "c:\Temp\!site[%site%]!\*.rdp"') do (
  set /a i+=1
  echo !i! - %%~nxa
  set mach[!i!]=%%~nxa
)
set /p m0=Enter Selection: 
echo mstsc !mach[%m0%]! /console
set /p sel=Would you like to launch another [y/n]? 
if /i "%sel%" EQU "y" Goto :start

此外,假设您的所有服务器都是2003.从2008年开始,我认为/ console已被弃用,而不是/ admin。如果是这种情况,根据您要连接的服务器版本,添加更多逻辑就足够了。

答案 1 :(得分:2)

@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION 
FOR /f "delims==" %%i IN ('SET s_ 2^>nul') DO SET "%%i="
SET "sourcedir=c:\sourcedir"
FOR /f "delims=" %%a IN ('dir/s/b/a-d "%sourcedir%\*.rdp"') DO (
 SET s_=%%~dpa
 FOR /f %%b IN ("!s_:~0,-1!") DO SET s_#%%~nb=Y&SET s_@%%~nb_%%~na=Y
)
CALL :showmenu "Location List" #
IF /i "%s_%"=="q" GOTO :EOF
SET s_site=%s_%
CALL :showmenu "Machine List for %s_site%" @ %s_site%
IF /i "%s_%"=="q" GOTO :EOF
SET s_machine=%s_%
ECHO(==============
ECHO site=%s_site% machine=%s_machine%
GOTO :EOF

:showmenu
SET s_items=1
CLS
ECHO(%~1
ECHO(
FOR /f "tokens=2,3delims=_%2=" %%i IN ('set s_%2') DO (
 IF "%3"=="" (
  CALL :showline %%i
 ) ELSE (
  IF "%3"=="%%i" CALL :showline %%j
 )
)

ECHO(
SET "s_="
SET /p "s_=Enter Selection : "
IF NOT DEFINED s_ SET s_=Q
IF /i "%s_%"=="q" GOTO :EOF
IF DEFINED s_%s_% CALL SET s_=%%s_%s_%%%&GOTO :EOF 
GOTO showmenu

:showline
SET "s_= %s_items%. "
ECHO %s_:~-4%%1
SET s_%s_items%=%1
SET /a s_items+=1
SET "s_%s_items%="
GOTO :eof

这种方式是自我调整的。不幸的是,它也使用了一些象形文字......

第一步是确保从环境中删除名称以s_开头的所有变量。对s_没有特别的意义 - 这正是我选择的。如果存在set s_变量,s_whatever=something的输出将为s_...形式。如果不存在,2>nul会抑制错误消息,但> 需要通过插入符号( ^ )进行转义,以告知cmd重定向是要执行的命令的一部分,而不是for命令。如果s_whatever=somethingfor /f将使用 = 作为分隔符解析该行,从而将s_whatever分配给指定的元变量%%i

下一步是从源目录开始查找所有 .RDP 文件名。 dir /s/b/a-d生成完整文件名的裸线(无页眉或页脚),从而抑制恰好与指定掩码匹配的任何目录名。

整个文件名已分配给%%a,因为delims=""即没有分隔符。 S_用作通用变量,并在%%a中分配文件名的驱动器和路径部分。然后删除s_的最后一个字符(它将是 \ ),for /f %%b将结果字符串解释为文件名。然后设置变量s_#sites_@site_machine(到Y,但它们可以设置为任何东西)

注意使用!s_:~0,-1!指定运行时值为s_的字符0..last-1 - 指定运行时值当SETLOCAL ENABLEDELAYEDEXPANSION处于活动状态时。

主程序的其余部分只需使用各种参数调用SHOWMENU两次,并将s_中返回的值分配给相应的变量。

SHOWMENU将项目数(s_items)设置为比可用项目数多1,清除屏幕并显示第一个子例程参数(%1)中的菜单标题 - 但引号被抑制(%~1) - 允许参数包含空格。

以下FOR/F标记SET(网站名称)或s_#(网站+机器名称)的s_@列表。使用 _ = 的分隔符以及#或@表示像s_#NSW=Y这样的行会将NSW分配给%%is_@NSW_Server01=Y之类的行将NSW分配给%%iServer01分配给%%j

选择适当的部分并传递给SHOWLINE例程。

然后将

s_用于用户输入。强制清除它意味着如果用户只按 ENTER ,它将保持未设置状态 - 否则它将保留其原始值。

我已经任意分配了Q的输入以退出,如果没有用户输入,那么也会退出。否则,如果设置了变量s_choicemade,则s_将设置为该值,并且从子例程返回EOF。如果选择无效,则不会设置s_invalidchoice,因此会重新显示菜单。

SHOWLINE程序将s_设置为空格 thelinenumber space 和然后显示paraeeter(%1),前面是该字符串的最后4个字符。这意味着如果项目编号超过9,则前导空间将被丢弃并且点将对齐。然后递增项目编号,以备下次选择。