选择对未来的默认流的选择性不好



PowerShell似乎将某些CMDLET与默认输出流相关联,并且在命令完成后不发布它,以意外的方式影响未来命令。它在这样做的方式上是不一致的,这使得在编写脚本时明确指导输出的情况下,生成可预测的输出不可能。

如果将命令放在单独的行,混合不同对象生成的cmdlet等,则会发生这种怪异。命令行,除非您混合在命令行上自动创建的对象中混合。

我给出了命令行交互式示例,但是如果将这些命令放入脚本中,则会在矛质线上运行脚本,然后运行脚本。

PS /home/dennis> get-date|select dayofweek ; get-date
DayOfWeek
---------
   Monday
   Monday
PS /home/dennis> "string1"|select length ; "string2"
Length
------
     7
string2

为了娱乐,请查看这个:

S /home/dennis> "string0" ;"string1"|select length ; get-host ;"string2" ;get-date; 567 ; get-host
string0
Length
------
     7
     1
string2
     1
567
     1
PS /home/dennis> cat test.ps1
"string0"
"string1"|select length
get-host
"string2"
get-date
567
(1..5)
get-host
PS /home/dennis> ./test.ps1
string0
Length
------
     7
     1
string2
     1
567
1
2
3
4
5
     1

...

这也会影响与不相同类型的对象,实际上,它会影响选择语句中甚至没有属性的对象。延迟不是一个选项,并解释说,用外主人或写入主持人将输出直接写入PowerShell输出设备,这使得创建将用于在管道中产生对象的脚本使其无用。它也弄乱了变量。观察:

PS /home/dennis> $d = get-date | select dayofweek ; $e = get-date ; $d ; $e
DayOfWeek
---------
   Monday
   Monday
PS /home/dennis> $d
DayOfWeek
---------
   Monday
PS /home/dennis> $e
Monday, August 5, 2019 12:33:47 PM

对于那些思考的人来说,这只是一个显示问题,可以编写脚本以正确显示它,我再说一遍,这使脚本无用,就像您可以在其他脚本中重复使用的工具。观察脚本中的管道如何影响独立的交互式外壳中的命令。

PS /home/dennis> cat test.ps1                    
"string0"
"string1"|select length
get-host
"string2"
get-date
567
get-host
PS /home/dennis> ./test.ps1|% {$_}               
string0
Length
------
     7
     1
string2
     1
567
     1
PS /home/dennis> ./test.ps1|% {write-host $_}
string0
@{Length=7}
System.Management.Automation.Internal.Host.InternalHost
string2
8/5/19 12:50:54 PM
567
System.Management.Automation.Internal.Host.InternalHost
PS /home/dennis> ./test.ps1|% {$_|out-host}  
string0
Length
------
     7

Name             : ConsoleHost
Version          : 6.2.2
InstanceId       : 4e46c643-1a9d-4c55-9151-b311f287a9cb
UI               : System.Management.Automation.Internal.Host.InternalHostUserInterface
CurrentCulture   : en-US
CurrentUICulture : en-US
PrivateData      : Microsoft.PowerShell.ConsoleHost+ConsoleColorProxy
DebuggerEnabled  : True
IsRunspacePushed : False
Runspace         : System.Management.Automation.Runspaces.LocalRunspace

string2
Monday, August 5, 2019 1:20:24 PM
567
Name             : ConsoleHost
Version          : 6.2.2
InstanceId       : 4e46c643-1a9d-4c55-9151-b311f287a9cb
UI               : System.Management.Automation.Internal.Host.InternalHostUserInterface
CurrentCulture   : en-US
CurrentUICulture : en-US
PrivateData      : Microsoft.PowerShell.ConsoleHost+ConsoleColorProxy
DebuggerEnabled  : True
IsRunspacePushed : False
Runspace         : System.Management.Automation.Runspaces.LocalRunspace

在任何shell脚本中,我希望命令将独立于上一个命令执行。这种行为背后的逻辑是什么?避免这种不可预测性的官方建议是什么?

我知道这很困惑。无论何时,Select-Object似乎都输出表,格式表实际上在后台运行。这些格式命令是一种幻想,并由格式文件控制。但是该物体下面仍然相同。

$a = [pscustomobject]@{name='Joe'}
$b = [pscustomobject]@{address='here'}
$a,$b | format-table
name
----
Joe

$a,$b | format-list 
name : Joe
address : here

其他解决方法:

$(get-date|select dayofweek ; get-date) | format-list
$("string1"|select length ; "string2") | format-list
$("string0" ;"string1"|select length ; get-host ;"string2" ;get-date; 567 ; get-host) | format-list
test.ps1 | format-list

$ d示例的问题是,分配给$ d只是第一个半龙的第一个语句。这是一个不同的问题。

$d = $(get-date | select dayofweek ; $e = get-date ; $d ; $e)
$d | format-list  # 3 objects, unless you repeat the last line

这样的示例可行,因为这两个命令均具有.format.ps1xml文件的输出对象类型。使用Select-Object后,输出是通用的PscustomObject。实际上,您可以尝试在任何脚本中将get-tate放在首位。

get-date;get-host

来自Windows PowerShell的行动:

Out-Default uses steppable pipelines to run the formatter 
cmdlets [like format-table] to do its rendering and then 
calls Out-Host to display the formatted output.

最新更新