本文介绍了是否可以在Powershell中有条件地进行管道,即只有满足条件才执行管道的元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我想做这样的事情:
< statement> | <过滤器1> | <过滤器2>如果<条件> | <过滤器3> | <过滤器4> | < filter5>
< statement>遍历< filter1>,然后它们遍历< filter2>只有当<条件>满足,然后通过剩余的过滤器,而不管< filter2>被应用。这相当于:
$ p $ if(< condition>){
< statement> | <过滤器1> | <过滤器2> | <过滤器3> | <过滤器4> | < filter5>
} else {
< statement> | <过滤器1> | <过滤器3> | <过滤器4> | < filter5>
$ b $ p
$ b 这对于给定过滤器应用于结果集的函数只有当某个开关被调用。如果条件过滤器发生在较长的流水线中,那么使用外部的if-block来写入会导致代码的重复,尤其是在有多个条件过滤器的情况下。
这是一个例子。以下函数显示给定帐户在给定目录子树中的权限(例如 Show-AccountPerms \\SERVERX\Marketing DOMAIN\jdoe
给出权限报告用户DOMAIN \ jdoe在\SERVERX\Marketing下的目录树中)。
函数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`
| {$ _。isinherited -eq'False'}`
| foreach {
if($ _。identityreference -eq $ account){
{0,-25} {1, -35} {2}-f $ _。identityreference,$ _。filesystemrights,$ dir
}
}
}
}
$ c $默认情况下,它只显示明确的权限(由 |执行),其中{$ _。isinherited -eq'False' (仅限于 |其中{$ _。psiscontainer}
过滤器)。
然而,如果调用-files开关,我想忽略 |其中{$ _。psiscontainer}
,并忽略 |其中{$ _。isinherited -eq'False'}
如果调用了-inherited开关。如果使用块,那么使用外部代码将会使代码增加4倍,其中将近75%是重复。有没有办法让这些过滤器在线,但指示PowerShell只适用于他们的相应开关是假的?
请注意,这只是一个例如,所以我对这个函数的特定解决方法不感兴趣。我正在寻找一个关于有条件的管道的一般性问题的答案,而不是如何完成这个特定的任务的解决方案。 解决方案
对不起,我不是故意放弃这个问题。所发布的答案并不是我所驾驶的,但是我发现在发布之后不久就可以做到这一点,而且很长一段时间没有回到现场。由于没有发布解决方案,这是我想出的。当我问这个问题的时候,并不是那么想的,而且这个问题也不是很漂亮,但显然这是唯一的方法: code><语句> | <过滤器1> | foreach {if(< condition>){$ _ | < filter2>}其他{$ _} | <过滤器3> | <过滤器4> | < filter5>
$ b $ p
$ b pre> |其中{$ _。psiscontainer}`
改成
| foreach {if(-not $ files){$ _ | {$ _。psiscontainer}} else {$ _}}`
和
|其中{$ _。isinherited -eq'False'}`
会改成
| foreach {if(-not $ inherited) {$ _ |其中{$ _。isinherited -eq'False'}} else {$ _}}`
是的,通常我会把它写成 | foreach {if($ files){$ _} else {$ _ | where {$ _。psiscontainer}}}
, | foreach {if($ inherited){$ _} else {$ _ | where {$ _。isinherited -eq'False'}}}
但是我这样做)
我希望可能会有更优雅的东西,它会评估过滤器前的一个条件,以确定是执行还是跳过阶段管道。像这样:
< statement> | <过滤器1> |如果(< condition>){< filter2>} <过滤器3>
(特殊情况 if
,not通常的意思,可以使用不同的关键字),也可能是
< statement> | <过滤器1> | (<条件>)? <过滤器2> | <过滤器3>
$ _
在条件下无效,除非它是在当前管道之外定义的,例如如果管道包含在 switch
语句中, $ _
in < condition>
会引用开关
语句的 $ _
。
我想我会向微软提供一个功能建议。这不仅使代码更优雅,而且更高效,因为如果是内置功能,可以评估< condition>
一次整个管道,而不是在每次迭代测试相同的独立条件。
I want to do something like this:
<statement> | <filter1> | <filter2> if <condition> | <filter3> | <filter4> | <filter5>
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>
}
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.
Here's an example. The following function shows the permissions a given account has in a given directory subtree (e.g. Show-AccountPerms \\SERVERX\Marketing DOMAIN\jdoe
gives a report of permissions that the user DOMAIN\jdoe has in the directory tree under \SERVERX\Marketing).
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
}
}
}
}
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).
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>
So, in the example, the line
|where {$_.psiscontainer} `
would be changed to
|foreach {if (-not $files) {$_ | where {$_.psiscontainer}} else {$_}} `
and
|where {$_.isinherited -eq 'False'} `
would be changed to
|foreach {if (-not $inherited) {$_ | where {$_.isinherited -eq 'False'}} else {$_}} `
(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>
(a special case of if
, not the usual meaning; a different keyword could be used), or maybe
<statement> | <filter1> | (<condition>) ? <filter2> | <filter3>
$_
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 $_
.
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中有条件地进行管道,即只有满足条件才执行管道的元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!