批处理列表文件夹内容,然后回显结果作为要设置为变量的选项

Batch list folder contents, then echo results as options to be set as variables

我通常喜欢尝试自己解决这些问题,但现在我不得不承认我不知道从哪里开始。希望有人能至少引导我朝着正确的方向前进。

我有一个包含许多 .txt 文件的文件夹

Text1.txt
Text2.txt
Text3.txt

在我的 windows bat 文件中,我需要列出所述文件夹的内容并将它们设置为要设置为变量的选项。 示例:

cls
echo[
echo[                  Please select an option
echo[        
echo                          (1) Text1
echo                          (2) Text2
echo                          (3) Text3
echo[
set /p option=Type your selection (1-3) and press ENTER=

if !option!==1 set var=Text1
if !option!==2 set var=Text2
if !option!==3 set var=Text3

非常感谢任何建议,这个论坛很棒。

*编辑 这是我试过的东西

cls
echo[
echo[                  Please select an option
echo[        
dir /b "*.txt"
echo[
set /p option=Type your selection (1-3) and press ENTER=

if !option!==1 set var=text1
if !option!==2 set var=text2
if !option!==3 set var=text3

它可以工作,但不会在选项前添加数字 (1),而且它们还左对齐而不是居中。

                  Please select an option

text1.txt
text2.txt
text3.txt

Type your selection (1-3) and press ENTER=

好吧,如果这是任何其他语言,你会怎么做?可能用您的目录列表填充一个数组,对吧?然后使用该数组将菜单选项与文件选择配对?好吧,不要让 Batch 语言没有数组这一事实阻止了您。它们很容易模拟。

@echo off & setlocal

rem // init array index
set file.length=0

rem // for each .txt file in the current directory
for %%I in (*.txt) do (

    rem // It's good practice only to enable delayed expansion when needed, as
    rem // otherwise it can mangle values containing exclamation marks
    setlocal enabledelayedexpansion
    
    rem // use a "for /f" command to endlocal while reading the value of
    rem // !file.length!.  This preserves exclamation marks in file names.
    for /f %%# in ("!file.length!") do endlocal & set "file[%%~#]=%%~I"
    
    rem // set /a doesn't require delayed expansion.  It just works.
    set /a file.ubound = file.length, file.length += 1 
)

rem // Display the collection of variables named file...something.
set file

给你。最后一行应该显示所有以 file 开头的变量的列表,包括模拟的 .length.ubound 属性。从那里,只需使用 for /L %%I in (0, 1, %file.ubound%) 来显示您的菜单。


还有更多内容。首先,我阅读了 解释 txt 文件的数量可以超过 50。默认情况下,Windows cmd 控制台是 24 行。将输出列化以便用户不必滚动不是很好吗?我写了一个实用程序脚本,它将采用一个平面列表并根据当前 cmd 控制台中的行数对其进行列化。将其另存为...

columnify.bat:

@if (@CodeSection == @Batch) @then
@echo off & setlocal

if "%~1"=="test" (
    rem // this errors if there's redirected input buffer waiting
    timeout /t 0 /nobreak >NUL 2>NUL && (
        echo Usage: command list output ^| %~nx0
        echo or %~nx0 ^< txtfile containing a list
        echo;
        echo Hit Ctrl-C to exit.
    )
    exit
)

for /f "usebackq tokens=1,2 delims=," %%I in (
    `powershell "(Get-Host).UI.RawUI.WindowSize.toString()"`
) do (
    rem // detect whether input buffer has content waiting
    start /b cmd /c "%~f0" test
    cscript /nologo /e:JScript "%~f0" %%I %%J
)

goto :EOF

@end // end Batch / begin JScript hybrid code

var stdin = WSH.CreateObject('Scripting.FileSystemObject').GetStandardStream(0).ReadAll();
    cols = WSH.Arguments(0) * 1 - 1,
    rows = WSH.Arguments(1) * 1 - 4;

var out = stdin.split(/\r?\n/), buffer = [], maxlen, col = 0;
if (rows > out.length) { rows = out.length; }

while (out.length) {
    buffer[col] = [];
    maxlen = 0;
    while (buffer[col].length < rows) {
        val = out.length ? out.shift() : '';
        buffer[col].push(val);
        if (maxlen < val.length) maxlen = val.length;
    }
    for (var i = buffer[col].length; i--;) {
        while (buffer[col][i].length < maxlen) { buffer[col][i] += ' '; }
    }
    col++;
}

for (var i=0; i < buffer[0].length; i++) {
    var line = [];
    for (var j=0; j < col; j++) {
        line.push(buffer[j][i]);
    }
    WSH.Echo(line.join(' ').substr(0, cols));
}

现在您的主脚本可以通过管道输出来使用 columnify.bat

@echo off & setlocal
rem // All the same stuff as above, but without the comments.

set file.length=0
for %%I in (*.txt) do (
    setlocal enabledelayedexpansion
    for /f %%# in ("!file.length!") do endlocal & set "file[%%~#]=%%~I"
    set /a file.ubound = file.length, file.length += 1 
)

cls

:displaymenu
echo Always press your luck.  Which file do you choose?
echo;
( for /L %%I in (0,1,%file.ubound%) do @(
        call echo %%I: %%file[%%~I]%%
) ) | columnify
echo;

set /P "choice=Enter a number: "
if %choice% GEQ 0 if %choice% LEQ %file.ubound% (
    setlocal enabledelayedexpansion
    echo You chose !file[%choice%]!.  Neat.
    endlocal
) else (
    cls
    powershell "write-host -f red 'Invalid response.  Enter a number between 0 and %file.ubound%.'"
    goto displaymenu
)

您可以构建不同的解决方案,这里有 2 个示例。

如果您只有几个文件可以使用 choice:

@echo off
setlocal enabledelayedexpansion
for /F "tokens=1,*delims=[]" %%i in ('dir /b /a:-d *.txt ^| find /v /n ""') do (
    echo %%i. %%j
    set "cnt=!cnt!%%i"
    set "fchoice%%i=%%~j"
)
choice /c %cnt% /m "Choose"
echo you chose !fchoice%errorlevel%!

如果你有很多文件,choice 可能不是一个可行的选择,然后恢复到 set /p:

@echo off
setlocal enabledelayedexpansion
for /F "tokens=1,*delims=[]" %%i in ('dir /b /a:-d *.txt ^| find /v /n ""') do (
    echo %%i. %%j
    set "cnt=!cnt!%%i"
    set "fchoice%%i=%%~j"
    set "fin=%%i"
)
set /p "chosen=Select a file by number: "
for /l %%i in (1,1,%fin%) do if "%chosen%" == "%%i" set "check=1"
if not defined check echo Incorrect choice selected & goto :EOF
echo you chose !fchoice%chosen%!