批处理文件列出文件夹并允许用户选择

时间:2013-06-12 03:41:03

标签: for-loop batch-file directory user-input

我搜索并搜索了一个解决方案(感觉是什么)一个独特的问题。许多 这里的答案非常有帮助,让我走了很长的路,但最后一点让我难过。

  • 我的批处理文件需要在具有变量名称的文件夹中打开可执行文件
  • 此文件夹可能位于两个目录之一
  • 这就是我原来的工作原理

    @ECHO OFF
    SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
    
    SET DIR1="%USERPROFILE%\AppData\Local\Application Workspace\Profiles"
    SET DIR2=C:\Application\SRW\Profiles
    
    IF NOT EXIST %DIR1% (
       GOTO PROFILE_2
     ) ELSE (
       GOTO PROFILE_1
     )
    
    :PROFILE_1
    for /f "delims=" %%A in ('dir %DIR1% /ad /b') do (
         set foldername=%%~nxA
         )
    SET DIR1=%DIR1:"=%
    SET DIR=%DIR1%\%foldername%\app.exe
    GOTO START_APP
    
    :PROFILE_2
    for /f "delims=" %%A in ('dir %DIR2% /ad /b') do (
         set foldername=%%~nxA
         )
    SET DIR=%DIR2%\%foldername%\app.exe
    GOTO START_APP
    
    :START_APP
    START "" /b "%DIR%"
    
    :EOF
    ENDLOCAL
    EXIT
    

当我发现某些用户可能在变量配置文件文件夹中有多个配置文件并且他们需要能够选择用于该给定任务的配置文件时,我就抛出了一个曲线球。现在我有一个变量配置文件夹和该文件夹中的一个或多个变量配置文件。

我找到了列出文件夹名称的代码,并在命令窗口中显示它们以供选择。

@echo off
cls
setlocal EnableDelayedExpansion

set /a count=0

for /d %%d in (*) do (
    set /a count+=1
    @echo !count!. %%d 
)
setlocal DisableDelayedExpansion

set /P selection="select folder number:"

我还发现这个例程允许用户从列表中选择一个文件,然后它应该将该文件名转换为变量。

Batch Script Programming -- How to allow a user to select a file by number from a list of files in a folder?

不幸的是,我无法让链接中的示例按原样工作,我不知道如何使其与文件夹名称一起使用,因为文件夹名称示例和文件名示例很接近但不够接近我不能理解该怎么办。即使它以某种方式设法工作,我怎么能在上面发布的原始代码中进行这样的例行工作?

此外,如果只有一个文件夹,我真的不希望强制用户选择文件夹。如果只存在一个文件夹,则应将其自动放入文件夹名称变量中,并且根本不会向用户显示任何内容。

我正在尝试做什么甚至可能?

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:2)

@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION 
::
:: Set count-of-targets and application name
::
SET /a targets=0
SET appname=app.exe
SET "dots=..."
::
:: clear all "$" variables
::
FOR /f "delims==" %%i IN ('set $ 2^>nul') DO SET "%%i="
::
:: look for app.exe in (1) userprofile... (2) \application\srw...
::
SET dir1="%USERPROFILE%\AppData\Local\Application Workspace\Profiles"
SET dir2="C:\Application\SRW\Profiles"
:: My testing - my directory names
SET dir1="c:\sourcedir"
SET dir2="C:\destdir\test dir"
FOR %%s IN (%dir1% %dir2%) DO (
 FOR /f "delims=" %%i IN ('dir /s /b "%%~s\%appname%"') DO ( CALL :process "%%~dpi"
 )
)
::
:: Now have TARGETS=#hits; $_n=full pathname; $n=directoryname
::
IF %targets%==1 SET mychoice=1&GOTO chosen
::
:: repeat a menu
::
:again
CLS
FOR /l %%i IN (1,1,%targets%) DO (
 IF %%i lss 10 (ECHO(%%i%dots%%dots:~0,1%!$%%i!) ELSE (ECHO(%%i%dots%!$%%i!)
)
SET mychoice=
SET /p mychoice="Please choose 1..%targets% : "
IF NOT DEFINED $_%mychoice% GOTO again
:chosen

CALL SET application="%%$_%mychoice%%%%appname%"

ECHO START "" /b %application%

GOTO :EOF
::
:: Parameter is quoted-full-pathname
::
:process
SET /a targets+=1
SET $_%targets%=%~1
SET $=%~1
FOR %%n IN ("%$:~0,-1%") DO SET $%targets%=%%~nxn
GOTO :eof

从你所说的,这应该有效。

第一步是设置。设置找到的目标数量和实际应用程序名称,并清除任何以“$”开头的变量名。

下一步是指定要使用的目录。我只是复制你的,然后用设置覆盖那些设置以适合我的机器 - 当然,你需要删除那些重写的行。请注意,名称应设置为引用...

接下来,扫描每个目录中的应用程序。每次找到实例时,请调用:process传递完整的路径名。

:process增加找到的目标数量,并将变量$_n设置为传递的完整路径名(反引号)然后将$设置为dequoted-full-pathname并使用语法-trick让FOR找到应用程序的直接目录。 %$:~0,-1%是完整路径名减去最后一个字符 - \所以结果看起来像文件名。然后将“文件名”分配给$n

目录扫描完成后,%targets%将包含er,目标数量。如果那是1,那么我们就拥有了所有我们需要的东西 - 我们只能选择目标编号1,以便为我们选择。

否则,清除屏幕并显示多行 - %targets% to be precise. The format is n ... immediatedirname`如果目标数量小于10,则会添加一个额外的点,以便长列表很好地排列。 然后询问行号。

此时,唯一存在的$_变量为$_1 .. $_%targets%,因此如果$ _%mychoice%存在,则必须是有效选择。如果没有定义,那么重复问题......

CALL SET application =“%% $ _%mychoice %%%% appname%”首先解析命令,然后再次解析它。在第一次解析之后,该行变为(如果mychoice=3SET application="%$_3%app.exe" so on the second occasion, application`被正确设置为应用程序的完整fulename - 并引用。

我的starting应用中没有太多意义,因为它不存在,所以我只是echo编辑它。


鉴于扩展要求:

你可能是从一个快捷方式开始的。假设您将该快捷方式最小化并在SETLOCAL

之后插入
SET "poweruser=%1"

之后添加
IF %targets%==1 SET mychoice=1&GOTO chosen

IF NOT DEFINED poweruser START "%username% - poweruser" "%~dpnx0" poweruser&GOTO :EOF 

并改变

GOTO :EOF

在标签:process之前

EXIT

因此,如果它未在poweruser模式下运行(因此poweruser NOT 已定义)且%targets% NOT 1(I假设它不会为0)然后此用户尚未设置为快捷方式中的poweruser,但 具有多个目标,因此作业将以poweruser模式重新启动(即最大化。)

请注意,"~dpnx0"之后的字符串实际上并不重要 - 只要它是一个字符串。我刚刚使用poweruser它的作用是告诉批处理它是在正常窗口中运行,而不是最小化。

对于powerusrs,如果您愿意将快捷方式设置为normal windowmaximised并在batchname之后的命令行中放置一个参数,则可以稍微加快该过程。没有参数并且最小化它将适合所有用户,因为如果找到超过1个目标,它将自动调整。

我试过这个。它对我有用。

答案 1 :(得分:1)

我分两步回答了你的问题。在第一篇文章中,我将原始代码翻译成更易读的代码。这是:

@ECHO OFF
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION

SET "DIR1=%USERPROFILE%\AppData\Local\Application Workspace\Profiles"
SET DIR2=C:\Application\SRW\Profiles

IF NOT EXIST "%DIR1%" (
   for /f "delims=" %%A in ('dir %DIR2% /ad /b') do (
      SET DIR=%DIR2%\%%~nxA\app.exe
   )
) ELSE (
   for /f "delims=" %%A in ('dir %DIR1% /ad /b') do (
      SET DIR=%DIR1%\%%~nxA\app.exe
   )
)

START "" /b "%DIR%"
ENDLOCAL
EXIT

您应首先检查以前的代码是否等同于原始代码。

在第二步中,我将配置文件选择添加到上一个代码:

@ECHO OFF
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION

SET "DIR1=%USERPROFILE%\AppData\Local\Application Workspace\Profiles"
SET DIR2=C:\Application\SRW\Profiles

IF NOT EXIST "%DIR1%" (
   for /f "delims=" %%A in ('dir %DIR2% /ad /b') do (
      SET DIR=%DIR2%\%%~nxA\app.exe
   )
) ELSE (
   call :SelectProfile
)

START "" /b "%DIR%"
ENDLOCAL
EXIT


:SelectProfile

rem Get a list of folders in User Profile dir
set count=0
for /f "delims=" %%A in ('dir %DIR1% /ad /b') do (
   set /A count+=1
   SET DIR[!count!]=%DIR1%\%%~nxA
)

rem Initialize the selected profile
set select=1
if %count% equ 1 goto endSelection

rem Show the profiles menu
cls
echo Available profiles:
echo/
for /L %%i in (1,1,%count%) do echo   %%i- !DIR[%%i]!
echo/

rem Let's the user to select the profile
:select
set select=1
set /P "select=Enter number of desired profile [first one]: "
if not defined DIR[!select!] goto select

:endSelection
SET DIR=!DIR[%select%]!\app.exe
exit /B

请注意,如果用户在答案中输入空格,之前的代码将失败。如果需要,可以修复此细节。