选项去哪里了?
Where do the options go?
我正在尝试将一个简单的批处理菜单文件升级为混合 batch/powershell 混合。我遇到了这个问题 - batch menu outlines and design - 它有一个很好的 Powershell 界面。但是,我不明白如何正确设置菜单选项!你能给我解释一下吗?
代码如下:
<# : Batch portion # Original Code by rojo@Whosebug
REM https://whosebug.com/users/1683264/rojo)
@echo off & setlocal enabledelayedexpansion
set "menu[0]=Open GenNBO Helper"
set "menu[1]=Open Jmol@NBO Viewer Helper"
set "menu[2]=Open Jmol *"
set "menu[3]=Start NBO"
set "menu[4]=Start Multiwfn"
set "menu[5]=EXIT"
set "default=5"
powershell -noprofile "iex (gc \"%~f0\" | out-string)"
echo Option Selected: !menu[%ERRORLEVEL%]!.
goto :EOF
:GENNBO
CLS
ECHO Starting GenNbo Helper v1.33
cd L:\GennboHelper\
start GennboHelper_1.33.jar
GOTO MENU
#JMOLNBO
:JMOLNBO
CLS
ECHO Starting JmolNbo Viewer Helper v2.1
cd L:\JmolNboVHelper2.1\
start JmolNbo21W.jar
GOTO MENU
#JMOL
:JMOL
CLS
ECHO Starting Jmol v14.30.1
cd L:\Jmol-14.30.1-binary\jmol-14.30.1
start Jmol.jar
GOTO MENU
#NBO
:NBO
CLS
ECHO Starting NBO 6.0 Environment CMD
cd L:\nbo6\
start C:\Windows\System32\cmd.exe /c L:\Portland\PGI\win64.10\pgi_dos.bat
GOTO MENU
#MWFN
:MWFN
CLS
ECHO Starting Multiwfn
L:\Multiwfn
start L:\Multiwfn\Multiwfn.exe
GOTO MENU
: end batch / begin PowerShell hybrid chimera #>
$menutitle = "=== MENU ==="
$menuprompt = "Use the arrow keys. Hit Enter to select."
$maxlen = $menuprompt.length + 6
$menu = gci env: | ?{ $_.Name -match "^menu\[\d+\]$" } | %{
$_.Value.trim()
$len = $_.Value.trim().Length + 6
if ($len -gt $maxlen) { $maxlen = $len }
}
[int]$selection = $env:default
$h = $Host.UI.RawUI.WindowSize.Height
$w = $Host.UI.RawUI.WindowSize.Width
$xpos = [math]::floor(($w - ($maxlen + 5)) / 2)
$ypos = [math]::floor(($h - ($menu.Length + 4)) / 3)
$offY = [console]::WindowTop;
$rect = New-Object Management.Automation.Host.Rectangle `
0,$offY,($w - 1),($offY+$ypos+$menu.length+4)
$buffer = $Host.UI.RawUI.GetBufferContents($rect)
function destroy {
$coords = New-Object Management.Automation.Host.Coordinates 0,$offY
$Host.UI.RawUI.SetBufferContents($coords,$buffer)
}
function getKey {
while (-not ((37..40 + 13 + 48..(47 + $menu.length)) -contains $x)) {
$x = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown').VirtualKeyCode
}
$x
}
# goo.gl/IAmdR6
function WriteTo-Pos ([string]$str, [int]$x = 0, [int]$y = 0,
[string]$bgc = [console]::BackgroundColor, [string]$fgc = [Console]::ForegroundColor) {
if($x -ge 0 -and $y -ge 0 -and $x -le [Console]::WindowWidth -and
$y -le [Console]::WindowHeight) {
$saveY = [console]::CursorTop
$offY = [console]::WindowTop
[console]::setcursorposition($x,$offY+$y)
Write-Host $str -b $bgc -f $fgc -nonewline
[console]::setcursorposition(0,$saveY)
}
}
function center([string]$what) {
$what = " $what "
$lpad = " " * [math]::max([math]::floor(($maxlen - $what.length) / 2), 0)
$rpad = " " * [math]::max(($maxlen - $what.length - $lpad.length), 0)
WriteTo-Pos "$lpad $what $rpad" $xpos $line blue yellow
}
function menu {
$line = $ypos
center $menutitle
$line++
center " "
$line++
for ($i=0; $item = $menu[$i]; $i++) {
# write-host $xpad -nonewline
$rtpad = " " * ($maxlen - $item.length)
if ($i -eq $selection) {
WriteTo-Pos " > $item <$rtpad" $xpos ($line++) yellow blue
} else {
WriteTo-Pos " $i`: $item $rtpad" $xpos ($line++) blue yellow
}
}
center " "
$line++
center $menuprompt
1
}
while (menu) {
[int]$key = getKey
switch ($key) {
37 {} # left or up
38 { if ($selection) { $selection-- }; break }
39 {} # right or down
40 { if ($selection -lt ($menu.length - 1)) { $selection++ }; break }
# number or enter
default { if ($key -gt 13) {$selection = $key - 48}; destroy; exit($selection) }
}
}
在 powershell ...
行之后,您只需回显所选的菜单点。您需要将其翻译成 goto
之类的 if "!menu[%errorlevel%]!"=="Open GenNBO Helper" goto :GENNBO
等(每个菜单条目一行)。
我建议改为更改标签并只使用一个 goto
:
powershell ...
echo Option Selected: !menu[%ERRORLEVEL%]!.
goto :menu%errorlevel%
goto :eof
:menu0
REM formerly :GENNBO
CLS
...
goto :menu
:menu1
REM formerly :JMOLNBO
...
etc.
这使用完全没有 CMD/Bat 东西的 powershell。 [咧嘴一笑]
它的作用...
- 定义了一个名为
Get-MenuChoice
的函数
这只是根据提供的菜单项数组显示一个菜单。然后它会得到一个响应,该响应与其中一项的数组索引相匹配,或者 x
用于退出。
- 将菜单列表定义为数组
- 将用户
$Choice
设置为空
- 开始一个
while
循环
- 使用函数得到一个有效的选择
- 使用
switch
结构来决定每个选择要做什么
- 写入 "do the thing" 匹配选择
您需要在此处添加自己的代码。它可能是 Start-Process
和 -Wait
参数。
- 如果选择
Exit
则退出
这是代码...
function Get-MenuChoice
{
[CmdletBinding ()]
Param
(
[Parameter (
Mandatory,
Position = 0
)]
[string[]]
$MenuList,
[Parameter (
Position = 1
)]
[string]
$Title,
[Parameter (
Position = 2
)]
[string]
$Prompt = 'Please enter a number from the above list or "x" to exit '
)
$ValidChoices = 0..$MenuList.GetUpperBound(0) + 'x'
$Choice = ''
while ([string]::IsNullOrEmpty($Choice))
{
Write-Host $Title
foreach ($Index in 0..$MenuList.GetUpperBound(0))
{
Write-Host ('{0} - {1}' -f $Index, $MenuList[$Index])
}
$Choice = Read-Host -Prompt $Prompt
Write-Host ''
if ($Choice -notin $ValidChoices)
{
[System.Console]::Beep(1000, 300)
Write-Warning ''
Write-Warning (' [ {0} ] is not a valid selection.' -f $Choice)
Write-Warning ' Please try again.'
Write-Warning ''
$Choice = ''
pause
}
}
# send it out to the caller
if ($Choice -eq 'x')
{
'Exit'
}
else
{
$Choice
}
} # end >>> function Get-MenuChoice
$MenuList = @(
'Open GenNBO Helper'
'Open Jmol@NBO Viewer Helper'
'Open Jmol *'
'Start NBO'
'Start Multiwfn'
)
$Choice = ''
while ([string]::IsNullOrEmpty($Choice))
{
$Choice = Get-MenuChoice -MenuList $MenuList
switch ($Choice)
{
0 {
'Do the [ {0} ] thing.' -f $MenuList[$Choice]
pause
$Choice = ''
break
}
1 {
'Do the [ {0} ] thing.' -f $MenuList[$Choice]
pause
$Choice = ''
break
}
2 {
'Do the [ {0} ] thing.' -f $MenuList[$Choice]
pause
$Choice = ''
break
}
3 {
'Do the [ {0} ] thing.' -f $MenuList[$Choice]
pause
$Choice = ''
break
}
4 {
'Do the [ {0} ] thing.' -f $MenuList[$Choice]
pause
$Choice = ''
break
}
'Exit' {
break
}
default {
'There is something wrong. [ {0} ] does not match any listed choice.' -f $Choice
pause
$Choice = ''
}
} # end >>> switch ($Choice)
} # end >>> while ([string]::IsNullOrEmpty($Choice))
输出...
0 - Open GenNBO Helper
1 - Open Jmol@NBO Viewer Helper
2 - Open Jmol *
3 - Start NBO
4 - Start Multiwfn
Please enter a number from the above list or "x" to exit : 5
WARNING:
WARNING: [ 5 ] is not a valid selection.
WARNING: Please try again.
WARNING:
Press Enter to continue...:
0 - Open GenNBO Helper
1 - Open Jmol@NBO Viewer Helper
2 - Open Jmol *
3 - Start NBO
4 - Start Multiwfn
Please enter a number from the above list or "x" to exit : 3
Do the [ Start NBO ] thing.
Press Enter to continue...:
0 - Open GenNBO Helper
1 - Open Jmol@NBO Viewer Helper
2 - Open Jmol *
3 - Start NBO
4 - Start Multiwfn
Please enter a number from the above list or "x" to exit : x
我正在尝试将一个简单的批处理菜单文件升级为混合 batch/powershell 混合。我遇到了这个问题 - batch menu outlines and design - 它有一个很好的 Powershell 界面。但是,我不明白如何正确设置菜单选项!你能给我解释一下吗?
代码如下:
<# : Batch portion # Original Code by rojo@Whosebug
REM https://whosebug.com/users/1683264/rojo)
@echo off & setlocal enabledelayedexpansion
set "menu[0]=Open GenNBO Helper"
set "menu[1]=Open Jmol@NBO Viewer Helper"
set "menu[2]=Open Jmol *"
set "menu[3]=Start NBO"
set "menu[4]=Start Multiwfn"
set "menu[5]=EXIT"
set "default=5"
powershell -noprofile "iex (gc \"%~f0\" | out-string)"
echo Option Selected: !menu[%ERRORLEVEL%]!.
goto :EOF
:GENNBO
CLS
ECHO Starting GenNbo Helper v1.33
cd L:\GennboHelper\
start GennboHelper_1.33.jar
GOTO MENU
#JMOLNBO
:JMOLNBO
CLS
ECHO Starting JmolNbo Viewer Helper v2.1
cd L:\JmolNboVHelper2.1\
start JmolNbo21W.jar
GOTO MENU
#JMOL
:JMOL
CLS
ECHO Starting Jmol v14.30.1
cd L:\Jmol-14.30.1-binary\jmol-14.30.1
start Jmol.jar
GOTO MENU
#NBO
:NBO
CLS
ECHO Starting NBO 6.0 Environment CMD
cd L:\nbo6\
start C:\Windows\System32\cmd.exe /c L:\Portland\PGI\win64.10\pgi_dos.bat
GOTO MENU
#MWFN
:MWFN
CLS
ECHO Starting Multiwfn
L:\Multiwfn
start L:\Multiwfn\Multiwfn.exe
GOTO MENU
: end batch / begin PowerShell hybrid chimera #>
$menutitle = "=== MENU ==="
$menuprompt = "Use the arrow keys. Hit Enter to select."
$maxlen = $menuprompt.length + 6
$menu = gci env: | ?{ $_.Name -match "^menu\[\d+\]$" } | %{
$_.Value.trim()
$len = $_.Value.trim().Length + 6
if ($len -gt $maxlen) { $maxlen = $len }
}
[int]$selection = $env:default
$h = $Host.UI.RawUI.WindowSize.Height
$w = $Host.UI.RawUI.WindowSize.Width
$xpos = [math]::floor(($w - ($maxlen + 5)) / 2)
$ypos = [math]::floor(($h - ($menu.Length + 4)) / 3)
$offY = [console]::WindowTop;
$rect = New-Object Management.Automation.Host.Rectangle `
0,$offY,($w - 1),($offY+$ypos+$menu.length+4)
$buffer = $Host.UI.RawUI.GetBufferContents($rect)
function destroy {
$coords = New-Object Management.Automation.Host.Coordinates 0,$offY
$Host.UI.RawUI.SetBufferContents($coords,$buffer)
}
function getKey {
while (-not ((37..40 + 13 + 48..(47 + $menu.length)) -contains $x)) {
$x = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown').VirtualKeyCode
}
$x
}
# goo.gl/IAmdR6
function WriteTo-Pos ([string]$str, [int]$x = 0, [int]$y = 0,
[string]$bgc = [console]::BackgroundColor, [string]$fgc = [Console]::ForegroundColor) {
if($x -ge 0 -and $y -ge 0 -and $x -le [Console]::WindowWidth -and
$y -le [Console]::WindowHeight) {
$saveY = [console]::CursorTop
$offY = [console]::WindowTop
[console]::setcursorposition($x,$offY+$y)
Write-Host $str -b $bgc -f $fgc -nonewline
[console]::setcursorposition(0,$saveY)
}
}
function center([string]$what) {
$what = " $what "
$lpad = " " * [math]::max([math]::floor(($maxlen - $what.length) / 2), 0)
$rpad = " " * [math]::max(($maxlen - $what.length - $lpad.length), 0)
WriteTo-Pos "$lpad $what $rpad" $xpos $line blue yellow
}
function menu {
$line = $ypos
center $menutitle
$line++
center " "
$line++
for ($i=0; $item = $menu[$i]; $i++) {
# write-host $xpad -nonewline
$rtpad = " " * ($maxlen - $item.length)
if ($i -eq $selection) {
WriteTo-Pos " > $item <$rtpad" $xpos ($line++) yellow blue
} else {
WriteTo-Pos " $i`: $item $rtpad" $xpos ($line++) blue yellow
}
}
center " "
$line++
center $menuprompt
1
}
while (menu) {
[int]$key = getKey
switch ($key) {
37 {} # left or up
38 { if ($selection) { $selection-- }; break }
39 {} # right or down
40 { if ($selection -lt ($menu.length - 1)) { $selection++ }; break }
# number or enter
default { if ($key -gt 13) {$selection = $key - 48}; destroy; exit($selection) }
}
}
在 powershell ...
行之后,您只需回显所选的菜单点。您需要将其翻译成 goto
之类的 if "!menu[%errorlevel%]!"=="Open GenNBO Helper" goto :GENNBO
等(每个菜单条目一行)。
我建议改为更改标签并只使用一个 goto
:
powershell ...
echo Option Selected: !menu[%ERRORLEVEL%]!.
goto :menu%errorlevel%
goto :eof
:menu0
REM formerly :GENNBO
CLS
...
goto :menu
:menu1
REM formerly :JMOLNBO
...
etc.
这使用完全没有 CMD/Bat 东西的 powershell。 [咧嘴一笑]
它的作用...
- 定义了一个名为
Get-MenuChoice
的函数 这只是根据提供的菜单项数组显示一个菜单。然后它会得到一个响应,该响应与其中一项的数组索引相匹配,或者x
用于退出。 - 将菜单列表定义为数组
- 将用户
$Choice
设置为空 - 开始一个
while
循环 - 使用函数得到一个有效的选择
- 使用
switch
结构来决定每个选择要做什么 - 写入 "do the thing" 匹配选择
您需要在此处添加自己的代码。它可能是Start-Process
和-Wait
参数。 - 如果选择
Exit
则退出
这是代码...
function Get-MenuChoice
{
[CmdletBinding ()]
Param
(
[Parameter (
Mandatory,
Position = 0
)]
[string[]]
$MenuList,
[Parameter (
Position = 1
)]
[string]
$Title,
[Parameter (
Position = 2
)]
[string]
$Prompt = 'Please enter a number from the above list or "x" to exit '
)
$ValidChoices = 0..$MenuList.GetUpperBound(0) + 'x'
$Choice = ''
while ([string]::IsNullOrEmpty($Choice))
{
Write-Host $Title
foreach ($Index in 0..$MenuList.GetUpperBound(0))
{
Write-Host ('{0} - {1}' -f $Index, $MenuList[$Index])
}
$Choice = Read-Host -Prompt $Prompt
Write-Host ''
if ($Choice -notin $ValidChoices)
{
[System.Console]::Beep(1000, 300)
Write-Warning ''
Write-Warning (' [ {0} ] is not a valid selection.' -f $Choice)
Write-Warning ' Please try again.'
Write-Warning ''
$Choice = ''
pause
}
}
# send it out to the caller
if ($Choice -eq 'x')
{
'Exit'
}
else
{
$Choice
}
} # end >>> function Get-MenuChoice
$MenuList = @(
'Open GenNBO Helper'
'Open Jmol@NBO Viewer Helper'
'Open Jmol *'
'Start NBO'
'Start Multiwfn'
)
$Choice = ''
while ([string]::IsNullOrEmpty($Choice))
{
$Choice = Get-MenuChoice -MenuList $MenuList
switch ($Choice)
{
0 {
'Do the [ {0} ] thing.' -f $MenuList[$Choice]
pause
$Choice = ''
break
}
1 {
'Do the [ {0} ] thing.' -f $MenuList[$Choice]
pause
$Choice = ''
break
}
2 {
'Do the [ {0} ] thing.' -f $MenuList[$Choice]
pause
$Choice = ''
break
}
3 {
'Do the [ {0} ] thing.' -f $MenuList[$Choice]
pause
$Choice = ''
break
}
4 {
'Do the [ {0} ] thing.' -f $MenuList[$Choice]
pause
$Choice = ''
break
}
'Exit' {
break
}
default {
'There is something wrong. [ {0} ] does not match any listed choice.' -f $Choice
pause
$Choice = ''
}
} # end >>> switch ($Choice)
} # end >>> while ([string]::IsNullOrEmpty($Choice))
输出...
0 - Open GenNBO Helper
1 - Open Jmol@NBO Viewer Helper
2 - Open Jmol *
3 - Start NBO
4 - Start Multiwfn
Please enter a number from the above list or "x" to exit : 5
WARNING:
WARNING: [ 5 ] is not a valid selection.
WARNING: Please try again.
WARNING:
Press Enter to continue...:
0 - Open GenNBO Helper
1 - Open Jmol@NBO Viewer Helper
2 - Open Jmol *
3 - Start NBO
4 - Start Multiwfn
Please enter a number from the above list or "x" to exit : 3
Do the [ Start NBO ] thing.
Press Enter to continue...:
0 - Open GenNBO Helper
1 - Open Jmol@NBO Viewer Helper
2 - Open Jmol *
3 - Start NBO
4 - Start Multiwfn
Please enter a number from the above list or "x" to exit : x