问题描述
我想做这样的事情:
<statement> | <filter1> | <filter2> if <condition> | <filter3> | <filter4> | <filter5>
<statement>的结果运行通过 ,然后它们运行通过 ;仅当<条件>满足,然后通过剩余的过滤器而不管<filter2>被应用.这相当于:
The results of <statement> run through <filter1>, then they run through <filter2> only if <condition> is met, then through the remaining filters regardless of whether <filter2> was applied. This is the equivalent of:
if (<condition>) {
<statement> | <filter1> | <filter2> | <filter3> | <filter4> | <filter5>
} else {
<statement> | <filter1> | <filter3> | <filter4> | <filter5>
}
这在仅在调用某个开关时才将给定过滤器应用于结果集的函数中很有用.如果条件过滤器出现在长管道的早期,用外部 if 块编写它会导致大量代码重复,尤其是在有多个条件过滤器的情况下.
This would be useful in functions where a given filter is applied to the result set only if a certain switch was invoked. If the conditional filter occurs early in a long pipeline, writing it with an outer if-block results in a lot of repetition of code, especially if there is more than one conditional filter.
这是一个例子.以下函数显示给定帐户在给定目录子树中的权限(例如 Show-AccountPerms \SERVERXMarketing DOMAINjdoe
给出用户 DOMAINjdoe 在目录中的权限报告SERVERXMarketing 下的树).
Here's an example. The following function shows the permissions a given account has in a given directory subtree (e.g. Show-AccountPerms \SERVERXMarketing DOMAINjdoe
gives a report of permissions that the user DOMAINjdoe has in the directory tree under SERVERXMarketing).
function Show-AccountPerms {
param (
[parameter(mandatory = $true)]$rootdir,
[parameter(mandatory = $true)]$account,
[switch]$files,
[switch]$inherited
)
gci -r $rootdir `
|where {$_.psiscontainer} `
|foreach {
$dir = $_.fullname
(get-acl $_.pspath).access `
| where {$_.isinherited -eq 'False'} `
|foreach {
if ($_.identityreference -eq $account) {
"{0,-25}{1,-35}{2}" -f $_.identityreference, $_.filesystemrights, $dir
}
}
}
}
默认情况下,它只显示显式权限(由 | 强制执行,其中 {$_.isinherited -eq 'False'}
过滤器),并且只显示目录(由 | 强制执行)其中 {$_.psiscontainer}
过滤器).
By default, it only shows explicit permissions (enforced by the | where {$_.isinherited -eq 'False'}
filter), and only on directories (enforced by the |where {$_.psiscontainer}
filter).
但是,如果调用了 -files 开关,我想忽略 |where {$_.psiscontainer}
,并忽略 |其中 {$_.isinherited -eq 'False'}
如果调用了 -inherited 开关.使用外部 if 块实现这一点将使代码翻两番,其中几乎 75% 将是重复的.有没有办法让这些过滤器保持在线,但指示 powershell 只应用它们对应的开关是假的?
However, I want to ignore |where {$_.psiscontainer}
if the -files switch is invoked, and ignore | where {$_.isinherited -eq 'False'}
if the -inherited switch is invoked. Accomplishing this with outer if blocks would quadruple the code, and almost 75% of it would be repetition. Is there a way to keep these filters in-line but instruct powershell to only apply them of the corresponding switch is false?
请注意,这只是一个示例,因此我对特定于此功能的任何变通方法不感兴趣.我正在寻找有关有条件管道的一般问题的答案,而不是如何完成此特定任务的解决方案.
Please note that this is just an example, so I'm not interested in any workarounds specific to this function. I'm looking for an answer to my general question regarding piping conditionally, not a solution for how to accomplish this particular task.
推荐答案
抱歉,我不是有意放弃这个问题的.发布的答案不是我想要的,但我在发布后不久就想出了一种方法,并且很长时间没有回到该网站.由于尚未发布解决方案,这就是我想出的.当我问这个问题时,这并不是我的想法,也不是太漂亮,但显然这是唯一的方法:
Sorry, I didn't mean to abandon this question. The answers that were posted weren't what I was driving at, but I figured out a way to do it shortly after posting, and didn't come back to the site for a long time. Since a solution hasn't been posted, here's what I came up with. It's not quite what I had in mind when I asked the question and it isn't too pretty, but apparently it's the only way to do it:
<statement> | <filter1> | foreach {if (<condition>) {$_ | <filter2>} else {$_} | <filter3> | <filter4> | <filter5>
因此,在示例中,该行
|where {$_.psiscontainer} `
将改为
|foreach {if (-not $files) {$_ | where {$_.psiscontainer}} else {$_}} `
和
|where {$_.isinherited -eq 'False'} `
将改为
|foreach {if (-not $inherited) {$_ | where {$_.isinherited -eq 'False'}} else {$_}} `
(是的,通常我会把它写成 |foreach {if ($files) {$_} else {$_ | where {$_.psiscontainer}}}
和 |foreach {if ($inherited) {$_} else {$_ | where {$_.isinherited -eq 'False'}}}
但为了清楚起见,我是这样做的.)
(Yes, normally I'd write that as |foreach {if ($files) {$_} else {$_ | where {$_.psiscontainer}}}
, and |foreach {if ($inherited) {$_} else {$_ | where {$_.isinherited -eq 'False'}}}
but I did it this way for clarity.)
我希望可能有更优雅的东西,它会评估过滤器前面的条件一次,以确定是执行还是跳过管道的一个阶段.像这样:
I was hoping there might be something more elegant, that would evaluate a condition in front of the filter once to determine whether to execute or skip a stage of the pipeline. Something like this:
<statement> | <filter1> | if (<condition>) {<filter2>} | <filter3>
(if
的特例,不是通常的意思;可以使用不同的关键字),或者
(a special case of if
, not the usual meaning; a different keyword could be used), or maybe
<statement> | <filter1> | (<condition>) ? <filter2> | <filter3>
$_
在条件中无效,除非它是在当前管道之外定义的,例如如果管道包含在 switch
语句中,$
将引用 中的 _
switch
语句的 $_
.
$_
would be invalid in the condition, unless it's defined outside the current pipeline, for example if the pipeline is contained within a switch
statement, $_
in the <condition>
would refer the switch
statement's $_
.
我想我会向 Microsoft 提出功能建议.这不仅会使代码更优雅,而且效率也会更高,因为如果它是一个内置特性, 可以被评估一次整个管道,而不是在每次迭代中测试相同的独立条件.
I think I'll make a feature suggestion to Microsoft. This would not only make the code more elegant, it would be more efficient as well, because if it's a built-in feature, <condition>
could be evaluated once for the entire pipeline, rather then testing the same independent condition in each iteration.
这篇关于是否可以在 Powershell 中有条件地进行管道传输,即仅在满足条件时才执行管道元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!