- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
起始前提:非常受限的环境,Windows 7 SP1,Powershell 3.0。使用外部库的可能性有限或不可能。
我正在尝试重写我之前创建的 bash 工具,这次使用的是 PowerShell。在 bash 中,我实现了自动完成功能,使该工具更加用户友好,我想对 PowerShell 版本做同样的事情。
bash 版本是这样工作的:
./launcher <Tab> => ./launcher test (or dev, prod, etc.)
./launcher test <Tab> => ./launcher test app1 (or app2, app3, etc.)
./launcher test app1 <Tab> => ./launcher test app1 command1 (or command2, command3, etc.).
如您所见,一切都是动态的。环境列表是动态的,应用程序列表是动态的,取决于所选的环境,命令列表也是动态的。
问题出在测试 → 应用程序连接上。我想根据用户已经选择的环境显示正确的应用程序。
使用 PowerShell 的 DynamicParam,我可以获得基于文件夹列表的动态环境列表。然而,我不能(或者至少我还没有找到如何)做另一个文件夹列表,但这次使用基于现有用户选择的变量。
当前代码:
function ParameterCompletion {
$RuntimeParameterDictionary = New-Object Management.Automation.RuntimeDefinedParameterDictionary
# Block 1.
$AttributeCollection = New-Object Collections.ObjectModel.Collection[System.Attribute]
$ParameterName = "Environment1"
$ParameterAttribute = New-Object Management.Automation.ParameterAttribute
$ParameterAttribute.Mandatory = $true
$ParameterAttribute.Position = 1
$AttributeCollection.Add($ParameterAttribute)
# End of block 1.
$parameterValues = $(Get-ChildItem -Path ".\configurations" -Directory | Select-Object -ExpandProperty Name)
$ValidateSetAttribute = New-Object Management.Automation.ValidateSetAttribute($parameterValues)
$AttributeCollection.Add($ValidateSetAttribute)
$RuntimeParameter = New-Object Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttributeCollection)
$RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter)
# Block 2: same thing as in block 1 just with 2 at the end of variables.
# Problem section: how can I change this line to include ".\configurations\${myVar}"?
# And what's the magic incantation to fill $myVar with the info I need?
$parameterValues2 = $(Get-ChildItem -Path ".\configurations" -Directory | Select-Object -ExpandProperty Name)
$ValidateSetAttribute2 = New-Object Management.Automation.ValidateSetAttribute($parameterValues2)
$AttributeCollection2.Add($ValidateSetAttribute2)
$RuntimeParameter2 = New-Object
Management.Automation.RuntimeDefinedParameter($ParameterName2, [string], $AttributeCollection2)
$RuntimeParameterDictionary.Add($ParameterName2, $RuntimeParameter2)
return $RuntimeParameterDictionary
}
function App {
[CmdletBinding()]
Param()
DynamicParam {
return ParameterCompletion "Environment1"
}
Begin {
$Environment = $PsBoundParameters["Environment1"]
}
Process {
}
}
最佳答案
我建议使用参数完成器,它们在 PowerShell 3 和 4 中半公开,在 5.0 及更高版本中完全公开。对于 v3 和 v4,底层功能已经存在,但您必须覆盖 TabExpansion2 内置函数才能使用它们。这对您自己的 session 没问题,但通常不赞成将执行此操作的工具分发到其他人的 session (想象一下,如果每个人都试图覆盖该功能)。 PowerShell 团队成员有一个名为 TabExpansionPlusPlus 的模块可以为您执行此操作.我知道我说过重写 TabExpansion2 很糟糕,但如果这个模块做到了也没关系 :)
当我需要支持版本 3 和 4 时,我会在模块中分发我的命令,并让模块检查是否存在“Register-ArgumentCompleter”命令,这是 v5+ 中的一个 cmdlet,如果您有TE++模块。如果模块找到它,它会注册任何完成器,如果没有,它会通知用户除非他们获得 TabExpansionPlusPlus 模块,否则参数完成将不起作用。
假设您有 TE++ 模块或 PSv5+,我认为这应该能让您走上正轨:
function launcher {
[CmdletBinding()]
param(
[string] $Environment1,
[string] $Environment2,
[string] $Environment3
)
$PSBoundParameters
}
1..3 | ForEach-Object {
Register-ArgumentCompleter -CommandName launcher -ParameterName "Environment${_}" -ScriptBlock {
param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)
$PathParts = $fakeBoundParameter.Keys | where { $_ -like 'Environment*' } | sort | ForEach-Object {
$fakeBoundParameter[$_]
}
Get-ChildItem -Path ".\configurations\$($PathParts -join '\')" -Directory -ErrorAction SilentlyContinue | select -ExpandProperty Name | where { $_ -like "${wordToComplete}*" } | ForEach-Object {
New-Object System.Management.Automation.CompletionResult (
$_,
$_,
'ParameterValue',
$_
)
}
}
}
为此,您当前的工作目录需要包含一个“配置”目录,并且您至少需要三个级别的子目录(阅读您的示例,看起来您要枚举一个目录,随着参数的添加,您将更深入地了解该结构)。目录的枚举现在不是很聪明,如果你跳过一个参数,你可以很容易地欺骗它,例如 launcher -Environment3 <TAB>
会尝试为您完成第一个子目录。
如果您始终拥有三个可用参数,则此方法有效。如果您需要可变参数,您仍然可以使用完成器,但它可能会有点棘手。
最大的缺点是您仍然必须验证用户的输入,因为完成者基本上只是建议,而用户不必使用这些建议。
如果你想使用动态参数,那就太疯狂了。可能有更好的方法,但我从来没有在不使用反射的情况下在命令行中看到动态参数的值,而此时你使用的功能可能会在下一个版本中改变(成员通常是'不公开是有原因的)。尝试在 DynamicParam {} block 内使用 $MyInvocation 很诱人,但是当用户在命令行中键入命令时它并没有被填充,而且它只显示一行命令而不使用反射。
下面是在 PowerShell 5.1 上测试的,所以我不能保证任何其他版本都有这些完全相同的类成员(它基于我第一次看到 Garrett Serack 做的事情)。与前面的示例一样,它依赖于当前工作目录中的 .\configurations 文件夹(如果没有,您将看不到任何 -Environment 参数)。
function badlauncher {
[CmdletBinding()]
param()
DynamicParam {
#region Get the arguments
# In it's current form, this will ignore parameter names, e.g., '-ParameterName ParameterValue' would ignore '-ParameterName',
# and only 'ParameterValue' would be in $UnboundArgs
$BindingFlags = [System.Reflection.BindingFlags] 'Instance, NonPublic, Public'
$Context = $PSCmdlet.GetType().GetProperty('Context', $BindingFlags).GetValue($PSCmdlet)
$CurrentCommandProcessor = $Context.GetType().GetProperty('CurrentCommandProcessor', $BindingFlags).GetValue($Context)
$ParameterBinder = $CurrentCommandProcessor.GetType().GetProperty('CmdletParameterBinderController', $BindingFlags).GetValue($CurrentCommandProcessor)
$UnboundArgs = @($ParameterBinder.GetType().GetProperty('UnboundArguments', $BindingFlags).GetValue($ParameterBinder) | where { $_ } | ForEach-Object {
try {
if (-not $_.GetType().GetProperty('ParameterNameSpecified', $BindingFlags).GetValue($_)) {
$_.GetType().GetProperty('ArgumentValue', $BindingFlags).GetValue($_)
}
}
catch {
# Don't do anything??
}
})
#endregion
$ParamDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
# Create an Environment parameter for each argument specified, plus one extra as long as there
# are valid subfolders under .\configurations
for ($i = 0; $i -le $UnboundArgs.Count; $i++) {
$ParameterName = "Environment$($i + 1)"
$ParamAttributes = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
$ParamAttributes.Add((New-Object Parameter))
$ParamAttributes[0].Position = $i
# Build the path that will be enumerated based on previous arguments
$PathSb = New-Object System.Text.StringBuilder
$PathSb.Append('.\configurations\') | Out-Null
for ($j = 0; $j -lt $i; $j++) {
$PathSb.AppendFormat('{0}\', $UnboundArgs[$j]) | Out-Null
}
$ValidParameterValues = Get-ChildItem -Path $PathSb.ToString() -Directory -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Name
if ($ValidParameterValues) {
$ParamAttributes.Add((New-Object ValidateSet $ValidParameterValues))
$ParamDictionary[$ParameterName] = New-Object System.Management.Automation.RuntimeDefinedParameter (
$ParameterName,
[string[]],
$ParamAttributes
)
}
}
return $ParamDictionary
}
process {
$PSBoundParameters
}
}
这个很酷的是只要有文件夹就可以一直运行,并且它会自动进行参数验证。当然,您通过使用反射获取所有这些私有(private)成员违反了 .NET 的法律,所以我认为这是一个糟糕而脆弱的解决方案,无论提出这个方案多么有趣。
关于bash - 动态参数值取决于另一个动态参数值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42768401/
我用 IntelliJ IDEA 2021.1 CE 在 流行!_OS 20.04 与 bash 5.0.17 . 问题造句:我将IntelliJ终端设置为/bin/bash通过 IntelliJ 设
给定如下命令: bash --shortcuts 我想显示一个快捷方式列表,就像在这个页面上一样: http://www.skorks.com/2009/09/bash-shortcuts-for-m
我有一个脚本可以操作数据、创建参数并将它们发送到第二个脚本。其中一个参数包含一个空格。 脚本1.sh: args=() args+=("A") args+=("1 2") args+=("B") .
我的脚本的“只运行一次”版本的一个非常简单的示例: ./myscript.sh var1 "var2 with spaces" var3 #!/bin/bash echo $1 #output: va
我想了解数字( double )在 bash 中是如何表示的,以及当我在 bash 中以十六进制格式打印数字时会发生什么。 根据 IEEE 754 标准,double 应由 64 位表示:52 位(1
我试图在 bash -c "..." 命令中获取 bash 脚本,但它不起作用。 如果我在 bash -c "..." 之外运行命令,它会起作用。 我需要使用 bash -c "..." 因为我想确保
如何检测我的 bash shell 中是否加载了 bash 补全包?从 bash-completion 的 2.1 版(包含在 Debian 8 中)开始,除了 BASH_COMPLETION_COM
我的 bash_profile 中有一个投影函数。现在我试图从 bash 脚本中调用这个函数,但是我得到了一个未找到的错误。如何使投影函数对 bash 脚本可见? 最佳答案 必须导出函数 export
我正在编写一个 bash 脚本,它接受许多命令行参数(可能包括空格)并通过登录 shell 将它们全部传递给程序 (/bin/some_program)。从 bash 脚本调用的登录 shell 将取
当我创建一个新的 bash 进程时,提示符默认为一个非常简单的提示符。我知道我可以编辑 .bashrc 等来更改它,但是有没有办法使用 bash 命令传递提示? 谢谢! 最佳答案 提示由 PS1、PS
好的,我希望这个问题有一定道理,但是 bash shell 和 bash 终端之间有什么区别?例子。当我第一次打开终端时,会提示我当前的目录和用户名。在终端窗口标题中显示 -bash- ,当我键入 e
我是 SBCL 的新手,我正在尝试从 bash 终端运行存储在文本文件中的 Lisp 脚本。 这是我在文件开头写的内容 http://www.sbcl.org/manual/#Running-from
我知道我们可以在 bash 中使用将十六进制转换为十进制 #!/bin/bash echo "Type a hex number" read hexNum echo $(( 16#$hexNum ))
我正在尝试在 bash 脚本中自动完成文件夹名称。如果我输入完整的文件夹名称,一切正常,但我不知道如何自动完成名称。有什么想法吗? repo() { cd ~/Desktop/_REPOS/$1 }
我想检查远程网站上的一些文件。 这里是bash命令生成计算文件md5的命令 [root]# head -n 3 zrcpathAll | awk '{print $3}' | xargs -I {}
是否有任何内置函数可以使用 bash shell 脚本从给定日期获取下周日(下周一、下周二等)?例如,2014 年 9 月 1 日之后的第一个星期日是什么时候?我预计 2014 年 9 月 7 日。
我一直在尝试根据表格重命名一些特定文件,但没有成功。它要么重命名所有文件,要么给出错误。 该目录包含数百个以长条形码命名的文件,我只想重命名包含模式 _1_ 的文件。 例子 barcode_1_bar
bash 中有没有办法用变量的内容替换文本文件中的占位符? 例如,我想发送一封电子邮件通知,如下所示: Dear Foo, Alert: blah blah blah blah blah blah
我有一个 bash 脚本,它在某些字符串上附加了一个重音字符,导致它失败,我找不到这些字符在哪里或如何进入那里。 这是一些示例输出: mv: cannot move â/tmp/myapp.zipâ
这个问题在这里已经有了答案: How do I place stdout on edit line? (1 个回答) Can a bash script prepopulate the prompt
我是一名优秀的程序员,十分优秀!