Powershell: 是时候使用“ PowerShell vZeroTechnicalDebt”和/或选择加入新功能/固定功能的机制,从而破坏向后兼容性?

创建于 2018-04-26  ·  69评论  ·  资料来源: PowerShell/PowerShell

请注意,“技术债务”一词在这里被宽松地使用,表示“累积的破坏行为,如果不破坏向后兼容性就无法解决”。


_Update_: @rjmholt已正式开始有关如何实施和管理重大更改的讨论:#13129。


注意:这个问题源于https://github.com/PowerShell/PowerShell/issues/5551#issuecomment -380522712,它只是为了开始讨论以查看是否存在接受此类更改的基本意愿。 最终,需要RFC。

多年来,PowerShell对向后兼容性的坚定承诺一直为社区服务。

另一方面,不可避免的副产品是技术债务的积累,需要记住例外情况,这是新来者的障碍。

当前存在的某些基本问题只能以向后兼容性为代价来解决,并且有两种(但不是互斥的)方式来解决该问题:

  • 实现了“ PowerShell vZeroTechnicalDebt”版本,该版本消除了所有技术债务,但丧失了向后兼容性(可能与使用语义版本控制指示兼容性的未来版本)

  • 向后兼容突破性功能/修复程序集成到现有代码库中,只能在_opt-in_的基础上严格使用。

我们愿意考虑哪些方法(如果有)?
一旦我们对此有所了解,就可以充实流程。

以下是一些现有的基本问题,这些问题只能以向后兼容为代价才能解决。 我相信其他人会想到更多:

  • 当前错误处理的复杂性和不一致性以及与“本机”(外部)程序的集成

  • 不一致,难以预测的偏好变量/公共参数继承-#4568

  • 由于[object[]]是基本集合类型而导致的性能问题-https : //github.com/PowerShell/PowerShell/issues/5643#issuecomment -378467986

    • 可以理解,尽管PowerShell永远无法与Unix实用程序的速度相提并论,但使它们之间的互操作可预测且尽可能轻松就显得尤为重要-请参阅其余问题的重新引用和解析。
  • 有问题的动态功能应按词法运行: https : breakcontinuehttps://github.com/ PowerShell / PowerShell-RFC / blob / master / 1-Draft / RFC0003-Lexical-Strict-Mode.md re Set-StrictMode (尽管后者可以在不破坏兼容性的情况下进行修复)

  • [psobject]相关的问题(尽管也许可以在不破坏兼容性的情况下加以解决):#5551,#5579,#4343,#5763

  • 不幸的-LiteralPath / -Path拆分-在https://github.com/PowerShell/PowerShell/issues/6714#issuecomment -383992749的简要说明以及在https://github.com上逃避的麻烦

  • 外部程序的报价错误-#3734,#5576(及其他)和相关的RFC失效

  • -Command-File CLI参数解析-https : //github.com/PowerShell/PowerShell/issues/4024#issuecomment -311541803,#3223-以及与POSIX之类的CLI的一般不对齐shells-#3743-包括默认情况下即使在非交互(脚本)调用中也加载用户配置文件-#992

  • 复合命令行参数-#6467-和看起来像参数的非参数标记-#6291,#6292和#6360的解析不一致且令人惊讶

  • https://github.com/PowerShell/PowerShell/issues/2035#issuecomment -323816221所述,对ValueFromRemainingArguments参数的处理中断,在#5955和#5122中显示了损坏的行为-返回https: //github.com/PowerShell/PowerShell/pull/2038

环境数据

撰写自:

PowerShell Core v6.0.2
Issue-Meta

最有用的评论

解决问题的成本很高,我认为这是PowerShell的技术负担,因为它们没有采用新的.NET概念

  • 泛型方法的类型参数的语言语法#5146

  • 引擎支持Extension Methods自动出现在类型系统中(就像它们以_compiled_ .Net语言一样)。 #2226

  • 对异步API#6716(和RFC )的语言支持

有一些令人遗憾的功能:

  • 我们可以基于类型提示(例如@KirkMunroFormatPx )而不是基于cmdlet来输出格式化对象的方法吗? #4594#4237#3886

  • 您是否将注册表提供者标准化为基于_content_的方式,而不是像演示属性提供者的工作方式那样? #5444

  • 您会深入重构PSProviders使其更容易编写吗? 可惜的是,需要两层抽象才能得出“ SHiPS”,并最终为人们提供了一种编写他们愿意使用的提供程序的方式

一个更大的问题呢:

我们是否愿意重新考虑“许多方法更好”的方法,并致力于“成功之道”的方法? 我的意思是,我们是否愿意删除被认为是“简单方法”但从根本上来说较差的功能,而只选择“正确方法”来做事情? 例如:

  • 使CmdletBinding始终打开
  • 将@()表示为List[PSObject]
  • 将@ {}设为Dictionary[PSObject, PSObject] (或Dictionary[string, PSObject] 😲)
  • 将_Process_设置为默认块
  • 甚至可以将_ValueFromPipelineByPropertyName_设置为默认;-)

所有69条评论

有趣。 我一直想知道为什么要使用.ps11来向PowerShell脚本添加某种语义版本控制,从而允许脚本指示其是否适应可能的重大更改。

解决问题的成本很高,我认为这是PowerShell的技术负担,因为它们没有采用新的.NET概念

  • 泛型方法的类型参数的语言语法#5146

  • 引擎支持Extension Methods自动出现在类型系统中(就像它们以_compiled_ .Net语言一样)。 #2226

  • 对异步API#6716(和RFC )的语言支持

有一些令人遗憾的功能:

  • 我们可以基于类型提示(例如@KirkMunroFormatPx )而不是基于cmdlet来输出格式化对象的方法吗? #4594#4237#3886

  • 您是否将注册表提供者标准化为基于_content_的方式,而不是像演示属性提供者的工作方式那样? #5444

  • 您会深入重构PSProviders使其更容易编写吗? 可惜的是,需要两层抽象才能得出“ SHiPS”,并最终为人们提供了一种编写他们愿意使用的提供程序的方式

一个更大的问题呢:

我们是否愿意重新考虑“许多方法更好”的方法,并致力于“成功之道”的方法? 我的意思是,我们是否愿意删除被认为是“简单方法”但从根本上来说较差的功能,而只选择“正确方法”来做事情? 例如:

  • 使CmdletBinding始终打开
  • 将@()表示为List[PSObject]
  • 将@ {}设为Dictionary[PSObject, PSObject] (或Dictionary[string, PSObject] 😲)
  • 将_Process_设置为默认块
  • 甚至可以将_ValueFromPipelineByPropertyName_设置为默认;-)

所有很棒的建议,@ Jaykul。

重新使用@()表示法是List[PSObject] :我认为我们可以更进一步,使用有效可扩展的集合类型作为PowerShell的基本集合类型,以便在[object[]]当前是(并且在内部以及返回集合时使用,没有类型转换性能损失); +使用存在

顺便说一句,将Process {}重新设置为函数中的默认块:这是Filter当前所做的,但仅限于-隐含- Process块,并且此函数变量似乎从未真正流行起来; 在Function的上下文中统一这两个对我来说很有意义。

有趣的是,现在在Azure PowerShell社区的一次电话会议上,他们将从AzureRm迁移到跨平台的新Az模块(没有单独的AzureRm.Core),并且所有命令前缀都从AzureRm更改为Az。 两者将并排一会儿,但是他们正在使用新的命令集。

太糟糕了,PowerShell还没有机会创建可以与Windows PowerShell并存运行的新可执行文件,但是这可能会脱离一些将其拖垮的旧文件。

试想一下,如果我们坚持下去会发生什么:
现实地说,要想出一个“无悔”的版本至少要花6个月的时间,而要重申这一点则要花6个月的时间。 然后,第三方模块也需要适应它,以使该版本有用,这至少还需要6个月才能获得合理的覆盖范围(请记住,某些模块永远不会)...然后考虑延迟和意料之外的问题,等等。。。所以,不,我认为这只是一厢情愿的事情,因为人们可以一劳永逸地摆脱一个版本中的所有技术债务(并且仍然可以开发并不仅仅是维护旧版本)。

我希望能有这样一个版本,但我认为只能一次缓慢地实现一项重大更改。 对于v6,许多重大更改已经被接受,但是我认为,如果一个版本中包含太多重大更改,则升级现有脚本/模块将变得过于复杂。 讨论最有价值的重大更改非常好,但是在没有LTS版本的pwsh之前,我认为现在不应该考虑对pwsh进行第二次培训,同时对现有的主流版本进行更实质性的更改。

@bergmeister同意。 但是,即使是核心路径上的相对较小的更改也会严重阻碍采用。 看一下Python3。花了10年的时间才真正流行起来。 通过更大的更改,谁知道Perl 6占主导地位将花费多长时间(他们花了15年的时间才提出了正确的建议,因此对于PowerShell ++ 1.5年似乎是乐观的:-))另一方面,PHP似乎定期打断东西,可能是由于方式和用途所致。

Python 3当然是恐怖节目,它真的流行吗? 我仍在运行2.7,并且不打算很快升级。 但是最近我对Perl 6的了解也很少。

我认为从Python那里学习的经验是将语言的重大更改与引擎的版本更改分开。 假设,PS 7引擎仍可以在不间断的更改模式下运行较早的脚本(.PS1)文件,而如果将该脚本标记为7感知(例如,扩展名为.PS7),则它们可以声明已被更新-并且至少需要运行PS 7。 希望有道理。

最好的成功故事可能是JavaScript / TypeScript / Babel。 转译器(具有源映射支持)似乎是语言发展的必经之路。

JavaScript是一种特例。 您几乎受其困扰,因此转码确实是唯一的选择。 Typescript是带有扩展名的“只是” Javascript,因此人们很容易采用。 任何JavaScript程序都是打字稿程序,因此您从拥有的内容开始,然后仅从那里添加注释。 另一方面,Dart是它自己的语言,但是可以转换为javascript或Chrome中的本机运行时(至少在某一时刻是计划)。 Dart似乎并没有在Google之外获得更多采用,可能是因为Dart是它自己的语言。

@BurtHarris

Python 3当然是恐怖节目,它真的流行吗?

上周我在阅读一篇文章,作者声称Python 3已达到临界质量。所有核心模块都可用,现在人们成群结队地迁移。 我们将会看到..

有趣。 我一直想知道为什么要使用.ps1中的1来向PowerShell脚本添加某种语义版本控制,从而允许脚本指示其是否适合可能的重大更改。

WRT .ps1 ,我们保留更改扩展名的权利,以防万一我们弄错了语言,从而导致运行时发生灾难性的更改,从而旧版本的脚本将无法正常工作。 但是更改扩展名也会导致大量工作,因为生态系统中的许多事物都与扩展名有关。 因此,这不是一件容易的事。 当然,作为Windows的一部分,如果我们分叉了扩展名​​,我们仍然必须维护这两个版本(类似于Python 2/3)。

@bergmeister

有效的关注点,但本着以下精神:

讨论最有价值的突破性变化是很好的

请分享您可能有的想法。

一次一次缓慢的重大变化

虽然针对不兼容更改的(按词法定义的)选择加入机制是一种解决方案,但我担心两件事:

  • 零星的介绍可能导致没有人能够记住什么功能需要哪个版本; 我想到了Perl(v5-)。

  • 代码库变得肿且难以维护,并且生成的二进制文件也同样blo肿,这至少(至少)损害了启动性能。

我之前已经说过:对我-这只是一个预感-v6 GA是在使老朋友不满意破坏性变化的同时,又承担了足够的负担以阻止在类似Unix的世界中采用的不幸的折衷方案。

就是说,考虑到PowerShell在类似Unix的世界中相对年轻,也许(仍然)有更多的意愿通过不兼容的更改来解决问题。 如@BrucePay所述,无论如何都将必须维护Windows PowerShell,并且它可以保持向后兼容的避风港。

我认为已经涵盖了这种重大变化所带来的负面影响的范围,我同意大多数观点。 我之所以写这封信,是因为我怀疑在更大的范围内,这些变化将在一开始就产生重大利益。 至少对于我使用PowerShell的方式而言。

OP包含以下语句:

另一方面,不可避免的副产品是技术债务的积累,需要记住例外情况,这是新来者的障碍。

该声明的隐含前提似乎是,做出这些各种重大更改将减轻记忆异常的负担。 确实,那将是一个伟大的结果。 但是,我对此表示怀疑。 PowerShell的行为刻意丰富。 这使得它既富有表现力又难以预测。 表现力和可预测性似乎相互影响,至少在我所熟悉的语言中是如此。

尽管我同意上述许多重大更改将在某些情况下提高可预测性,但语言的许多不可预测和令人惊讶的方面仍将保留。 尽管花了很多年编写PowerShell的经验,但我仍然经常对PowerShell的行为感到惊讶,该行为似乎是设计使然,不应更改。 我想到的一些最新示例如下:

  • [scriptblock]参数的条件延迟绑定(#6419)
  • 确切地说,何时发生隐式枚举(#5832)
  • 在参数绑定期间将[AutomationNull]::Value$null (与#6357相关)
  • breakcontinue对管道中控制流的影响(#5811)
  • 吐出$nullSO )会发生什么
  • 跨会话状态使用脚本块如何影响$_SO 1SO 2

我希望这些示例只是我尚未发现的许多其他精心设计但令人惊讶的细微差别的一小部分。 我选择这些示例是因为

  1. 它们表示在PowerShell中可能无法改进的行为,并且
  2. 我不希望在阅读或编写PowerShell时可靠地发现它们的所有含义。

我对此很好。 绝大多数令人惊讶的PowerShell行为不会对我使用PowerShell的成功产生持久影响。 在开发过程中,几乎总是立即通过测试发现令人惊讶的行为。 我从漏接的事物中学习并使用它来改进我的测试策略。 无论这些令人惊讶的行为是可以消除的形式还是必须保留的形式,都是如此。

无论是否进行了上述提议的重大更改,PowerShell都不会变得如此可预测,以至于我可以大大减少测试范围。 换句话说,以我使用PowerShell的方式,我认为通过进行上述提议的重大更改甚至没有很大的上升空间。

(顺便说一句,谢谢@ mklement0直接问这个问题。这已经引起我一段时间了。很高兴看到每个人都有机会发表自己的看法。)

谢谢@ alx9r。

我认为区分_intrinsic_复杂度和_extrinsic_复杂度很重要:

  • 内在的复杂性源于所实现概念的内在复杂性,在PowerShell中,它具有两个主要来源:内在的复杂性源自引入新的范式(基于对象的管道)并结合了两个不同的世界(shell语法和编程语言语法) ),以及与多个不同的外部世界进行交互所带来的_external_复杂性。

  • _外部的复杂性源于抽象的泄漏和不一致。

    • 这样的复杂性应该被消除。
    • 如果由于向后兼容性的考虑而无法解决此问题,则应将这种复杂性记录为已知问题。

    • 脚本模块变量作用域行为(您在$_的上下文中引用)不仅仅是一个怪癖:它是一个主要问题的根本原因,前面提到的#4568。

    • 您提到的所有其他问题都令我感到惊讶,因为它们都以不一致的形式出现,没有明显的(记录在案)基本原理或益处,因此使我感到属于非固有类别(而不是精心设计的结果):

      • 使用$null进行散列传递_no_参数而不是位置$null参数更有意义。
      • 为何在_parameter binding_期间将[System.Management.Automation.Internal.AutomationNull]::Value转换为$null ,即使类型保留在_direct变量Assignment_中? 参见https://github.com/PowerShell/PowerShell/issues/9150#issuecomment -473743805
      • 如果没有找到封闭循环,则在整个调用堆栈中对breakcontinue进行_dynamic_作用域有什么好处?

尽管仅凭功能的丰富性和不同世界的加入就很难记住所有必需的固有复杂性,但最大限度地减小固有复杂性仍然很重要。

必须首先测试您想要的方法而不仅仅知道并相信它会起作用-或由于意外的行为而使事情意外中断-是严重的生产力(和乐趣)障碍(即使PowerShell值得称赞,也很容易以交互方式测试行为) )。

它归结为扎实的概念(不违反直观的期望),描述性的命名和良好的文档说明:

如果我不知道/不确定我是否记得正确,我需要知道在哪里查找它,并确信也记录了已知问题和边缘情况_(作为常规帮助主题的一部分或通过来自那里)。

因此,即使我们决定不消除外部复杂性,也至少可以系统地对其进行记录-并且这里的讨论可以作为编译“陷阱画廊”的起点(其中还可能包含不可避免的_intrinsic_复杂性的情况,可能令人惊讶)。

我们至少可以系统地记录它-此处的讨论可以作为编译“陷阱画廊”的起点

罗曼·库兹敏(Roman Kuzmin)收集此类画廊已有一段时间了,这里: https :

谢谢@HumanEquivalentUnit-看起来很棒。

除此线程中收集的问题外,它还可以构成画廊的基础,该画廊是_official_文档的一部分,并在适当时增加了每个条目:

  • 一种设计原理,该原理说明了为什么行为(尽管也许令人惊讶)毕竟是合理的(正确地框架化的解释可能会使惊喜元素消失)

  • 对问题的确认,指出:

    • 任一个:为了向后兼容,它不会被修复。
    • 或者:正在考虑未来的变化
    • 或:该问题已在PS _Core_中解决

奇怪的是,不得不问是否要到“ PowerShell vZeroTechnicalDebt”的时间_

正是为此,需要一个版本命令。

如果新版本中出现问题,我们唯一的痛苦就是必须学习和学习通常很小的差异。

但是,我们(最终)得到了一个平台,该平台在内核中的每次迭代中都会真正变得更好。 而且更容易维护。

不,用新的知识和技术开始不良的设计和决策绝不是问题。

另外,要使活人摆脱僵局,编写一个处理良好的函数或cmdlet来处理主机的本机文件系统与filesystemprovider之间的神奇区别仍然非常困难。 这种细微差别的代码很难编写,而且常常会出错。 这是我七八年前回答的关于stackoverflow的帖子,仍然有效:

https://stackoverflow.com/questions/8505294/how-do-i-deal-with-paths-when-writing-a-powershell-cmdlet

参考:#8495

有一些奇怪的运算符优先级规则值得修改:

PS> 1, 2, 2 + 1, 4, 4 + 1
1
2
2
1
4
4
1

在大多数语言中,人们通常希望它是输出:

1
2
3
4
5

有一个优点和缺点的选项是一个新功能标记,用于启用所有“理想”行为,因此可以选择加入。 如果我们有遥测表明大多数用法已转移到新行为,则可以将其翻转以使其退出。 这可能只是个白日梦,因为我还没有看到现实世界中有这样一个模型能起作用的案例...

确实,这是_nice_,但是鉴于该线程中某些修订的相当……彻底……的性质,它可能会潜在地将脚本“正常”与“实验性”之间完全兼容,并且可能分成几部分,取决于个人启用了哪些标志。

这意味着我们不能真正以这种方式依赖于任何具有实验性的功能,也不能编写依赖于它们的脚本和模块,除非我们在文档页面上附加了巨大的警告,或者除非某些标志可能会阻止其导入已启用。

这是可以避免的,但是...如果我们可以随意在每个模块范围内启用和禁用特定的实验功能。 但是,考虑到这只会使问题进一步复杂化,我什至不确定这是否是一个特别好的解决方案。

@ vexx32只是要清楚一点,我并不是在建议一个experimental标志,该标志最终将变成非实验性的。 我在想些不同的东西(也许会像Enable-PSFeature那样得到官方支持(这样可以保护它免受实验性功能的破坏)。 我还认为这将是一个单独的标志,您可以将这些新的重大更改作为一个整体而不是单个地选择加入。

哦,那样的话...是的,绝对是。 这样一来,我们就能将所有内容整齐地打包在一个保护伞下,并加以实际使用。 比我想的要好得多! 😄

@ jszabo98是基于#8512在此处编译的问题列表的补充:

-and-or意外地具有_same_优先级,而在大多数语言(包括C#)中, -and优先级高于-or

违反期望的示例表达式:

PS> $true -or $true -and $false
False

由于左联想性和-and-or具有相同的优先级,因此以上内容被评估为($true -or $true) -and $false而不是预期的$true -or ($true -and $false)

这可能只是个白日梦,因为我还没有看到现实世界中有这样一个模型能起作用的案例...

实际上,我们已经有了一个可以在全世界使用的模型-LTS。 MSFT使用它来开发Windows10。该模型用于开发Unix发行版。
对我们来说,这意味着我们可以每两年发布LTS PowerShell Core版本,并将它们包含在Windows 10 LTS版本和Unix LTS版本中。 (一个问题是同步LTS版本的Windows和Unix发行日期。我想MSFT可以与主要的Unix公司进行谈判。)
在这两年中,我们正在收集较小的重大更改,将更重大的重大更改转移到下一个周期。
对于每个新的LTS版本,ScriptAnalyzer应该获得一组新规则以促进脚本迁移。
使用此模型,关键的产品和脚本只需经过全面的测试和迁移即可从先前的版本跳至下一版本。

当我逐步(从版本进行版本迁移)将旧系统从PHP 4版本迁移到下一PHP版本时,便使用了这种方法,直到达到受支持的PHP 5.x版本为止。 在每个步骤中,我都必须进行相对较小和快速的更改,然后系统继续工作一段时间,直到进行下一步。

更新:它应该与.Net Core LTS版本同步。 我希望下一个LTS是.Net Core 3.1,而该版本应该是PowerShell Core6.x。

老实说这听起来像是PowerShell Core的一个真正_great_想法。 这将使我们能够做出这样的重大更改,这确实可以帮助它向前发展,而不会使兼容性负担过重,同时也不会在LTS版本之间的过渡中给过多的重大更改造成负担。

参考: https :

$var是一个数组时, Get-Variable -ValueOnly -Name myVar | Should -Be $var断言失败。

这是因为Get-Variable -ValueOnly不使用WriteObject()的枚举重载。

关于具有不同功能集和重大更改的Powershell的多个版本:我们已经在传统和核心中拥有了。 乍一看似乎很糟糕,但可能为将来提供一个可行的模型。 跟我在一起...

在运行实际脚本之前,我们必须设置几乎所有使用powershell来调用核心pwsh.exe的进程,因为Windows计划的任务,jenkins和许多环境都不知道Powershell核心。 这样做是因为我们使用的功能仅在特定的PS版本中可用。

在无法强制调用内核的情况下,我们必须让每个脚本检查其运行在哪个PS版本上,然后在主机系统上使用适当的PS版本自行调用。 无论我们使用什么技巧来使正确的代码在正确的环境中运行,我们经常将所有环境和参数传递给已经在运行的同一脚本。

那就是UNIX的哲学。 使工具做一件事并做好。 然后组合工具以创建大于其各部分之和的整体。 这是脚本编写的世界,我们可以一直对其他实用程序进行subshel​​l调用并处理结果。 从历史上看,这就是脚本。 Powershell会通过尝试使所有代码都保持本机化而趋向于一种奇怪的约定,但这仅仅是一个约定,而不是一项要求。 PS可以访问操作系统和所有可用的实用程序,就像Unix Shell脚本一样。

如果core的文件扩展名已更新为.ps6,则Powershell引擎可以为我们完成工作,这将更加容易。 只要对Powershell的每个调用都通过环境并将输出,错误,警告,异常返回给另一个,则Powershell的每个二进制版本都可以保持彼此独立-我们现在必须尽力而为。 只要引擎知道要运行哪个版本,就不必在引擎中具有向后兼容的标志。 涉及的上下文切换已经在发生,因此我们已经处于最坏的情况下。

除非我们继续以明确的方式破坏事物,否则我们将永远被迫在Powershell中使用可怕的骇客。 突破性的变化不会使我们的生活变得比现在更加困难。 或者,如果我们使用渐进式的,持续的改进,并且让引擎对切换上下文进行繁重的工作,那么我们的代码(和生存期)将会更好。

@ jtmoree-kahalamgmt-com感谢您的反馈! 随时打开新问题,以分享您的经验和反馈并询问新的有用功能。

如果core的文件扩展名已更新为.ps6,则Powershell引擎可以为我们完成工作,这将更加容易。

参见https://github.com/PowerShell/PowerShell/issues/2013#issuecomment -247987977

我根据您的反馈创建了https://github.com/PowerShell/PowerShell/issues/9138

Python 3当然是恐怖节目,它真的流行吗? 我仍在运行2.7,并且不打算很快升级。 但是最近我对Perl 6的了解也很少。

我认为从Python那里学习的经验是将语言的重大更改与引擎的版本更改分开。 假设,PS 7引擎仍可以在不间断的更改模式下运行较早的脚本(.PS1)文件,而如果将该脚本标记为7感知(例如,扩展名为.PS7),则它们可以声明已被更新-并且至少需要运行PS 7。 希望有道理。

我认为将Python 3称为恐怖表演过于戏剧化。 如果我查看PyPi顶部下载的软件包,并获取有关v2与v3下载的各个软件包元数据,我发现v3现在几乎打破了所有顶级软件包的33%渗透率,而对于像Ken Reitz的请求库这样的较新库,它的将近50/50的份额:昨天v3的下载量为68.5万,v2的下载量为875k。

长期困扰Python 3的主要问题是科学界对熊猫和pysci的支持。 但是,在最新统计数据中,科学界现在更喜欢Python 3而不是Python 2: https: //pypistats.org/packages/pandas 231k v3下载,而175k v2下载。

正如著名的爱德华兹·戴明(W. Edwards Deming)博士所说:“我们相信上帝,所有其他人,都带来数据!” 也许您可以编写PowerShell脚本来分析PyPi数据集,并告诉我Python 3如何使用数据: https ://packaging.python.org/guides/analyzing-pypi-package-downloads/

我很乐意(按此确切顺序):

  1. 更易于使用的模块系统可产生良好的堆栈跟踪。

    • 例如,psm1文件允许描述有关函数加载方式的任意规则,但这会导致隐式堆栈跟踪,其中所有函数在逻辑上均被组合到psm1文件中。 这意味着堆栈轨迹上的行号与巧克力茶壶一样有用。
  2. 替换PowerShell默认错误对象字符串格式,这将吞噬基于堆栈的von Neumann架构中99%的编程实用性。

    • C#或多或少地获得了这一权利。 PowerShell太聪明了。
  3. 修复null重定向,以便将输出流重定向到null设备的三种不同方式在性能上相同。

  4. 修复动态范围

function a($f) {& $f}
function main() {
    $f = {write-host 'success'}
    a {& $f} # stack-overflow
    a {& $f}.getnewclosure() # okay
}
[void] (main)
  1. 修复变量捕获
set-strictmode -version 'latest'
$erroractionpreference = 'stop'

function main() {
    $a = 'foo'
    $f = {
        $g = {$a}.getnewclosure()
        & $g # "variable '$a' cannot be retrieved because it has not been set."
    }.getnewclosure()
    & $f
}

main
  1. 输出积累; return与其他语言的功能不同; 修理它。

  2. PowerShell没有用于处理对象外部资源的语法糖

  3. 重写PowerShellGet。 好厉害具有数百行代码的功能,可吞咽的异常,没有测试覆盖率。

  4. 摆脱模块缓存的工作方式。

    • 缓存不是线程安全的。 WTF?
    • 出于分析目的而缓存模块的整个概念就是浪费。 我意识到Microsoft内部对此功能提供了巨大的支持,因为PowerShell的运行速度是如此之慢,但是请参阅我的下一个建议,以获取真正的修复。
    • 清除AnalysisCache的唯一方法是重新启动PowerShell.exe
    • 用于分析目的的模块缓存将分析紧密耦合到模块的运行时状态。
  5. 提供类似于Py文件编译为pyc文件以提高性能的“编译模块”。

  6. 添加$none文字

    • 考虑在许多地方用$none替换$null
    • 重新考虑ParameterSetName的工作方式,并允许将$none特殊值传递给参数,这样我就无需编写疯狂的switch语句来以5种不同的方式调用代码。 COM和C#dynamic可以正确地做到这一点-PowerShell造成了灾难。 示例将是如何根据订阅发生类型在ReportingServicesTools模块中动态映射SSRS报告的部署配置。 我宁愿只传递一袋属性,并让该方法在内部处理复杂性,而不是在外部给最终用户施加复杂性。 ParameterSetName仅作为概念用作模板有用,不适用于对其进行编程。 它使智能多态性与智能感知混为一谈。

@jzabroski关于ErrorRecord格式,还有一个单独的问题用于讨论该问题: https :

您的其他一些请求可能是加性的,并且不会中断,因此这些应该是单独的问题。 这个特定问题正在讨论如果有机会并且可以证明进行PS新主要版本的合理性,请要求进行更改。

@jzabroski关于ErrorRecord格式,还有一个单独的问题用于讨论该问题:#3647,由于格式不被认为是重大更改,因此我们可以在那里进行改进。

_为什么_这不是一个重大变化? 因为开发人员不应该首先对错误消息中的字符串进行模式匹配? 我想那是有效的。 但这仍然会打断下游消费者。

您的其他一些请求可能是加性的,并且不会中断,因此这些应该是单独的问题。

您认为哪些可能加成? 我可以为他们创建问题,这样我们就不会偏离讨论的范围,但是今天早上我仔细地整理了这份清单。 我讨厌PowerShell,带着狂暴的热情和狂暴的雷鸣和闪电般的爆炸。 PowerShell是带有割肉刀的保龄球。 作为工程师,我最难堪的前5个时刻都是在使用PowerShell时发生的。 我再也回不来那个时间了。

我已经更新了我的建议,以弄清楚为什么这些建议是突破性的(并且很棒)。

输出积累; return与其他语言的功能不同; 修理它。

returnclass方法中的行为确实符合您的预期。 对于shell脚本环境(例如Korn shell和Bash),常规/高级PS函数中的“输出累积”方式非常典型。 也就是说,从控制台复制几个命令并将它们放入一个函数中。 调用该函数时,它会从每个命令输出,就像您从控制台执行这些命令时一样。

我对PowerShell的主要抱怨是,在常规/高级函数情况下, return应该永远不要接受参数。 因为类似:

return $foo

实际执行为:

$foo
return

这给人们一种感觉,他们可以通过使用return来控制输出,而他们不能。

returnclass方法中的行为确实符合您的预期。 对于shell脚本环境(例如Korn shell和Bash),常规/高级PS函数中的“输出累积”方式非常典型。

我听到有人这样说,包括@BrucePay (请参阅下面的我的重点,引用他的话),但最重要的是:

只有在PowerShell中,我们才有这种不合逻辑的“返回不返回”的废话,并且输出会累积。 这是光荣的内存泄漏,您应该这样考虑。

坦白说,在PowerShell中的所有地方,我都会搜索短语“问题”,我可以在vZeroTechnicalDebt列表中添加一些内容。 这是Bruce关于return语句的内容:

7.3从函数返回值
现在该讨论从函数返回值了。 我们一直都在这样做,但是我们需要强调一些事情。 因为PowerShell是外壳程序,所以它不返回结果-它写入输出或发出对象。 如您所见,任何表达式或管道的结果都是将结果对象发送给调用方。 在命令行中,如果键入三个用分号分隔的表达式,则将输出所有三个语句的结果:
[...]
在传统方法中,您必须初始化结果变量$result ,以保存要生成的数组,将每个元素添加到数组,然后发出数组:

PS (16) > function tradnum
> {
> $result = @()
> $i=1
> while ($i -le 10)
> {
> $result += $i
> $i++
> }
> $result
> }

这段代码要复杂得多:您现在必须在函数中管理两个变量,而不是一个。 如果您使用的语言无法自动扩展数组的大小,那么它将变得更加复杂,因为您必须添加代码来手动调整数组的大小。 而且即使PowerShell将自动调整数组的大小,与捕获流输出相比,效率也不高。 关键是让您考虑如何使用PowerShell提供的功能来改进
您的代码。 如果发现自己编写了显式构造数组的代码,请考虑查看它是否可以重写以利用流技术。

我认为此功能背后的动机很不错,但是有很多更简洁易读的方法可以实现相同的目标:从单个对象隐式提升为对象集合。 而且,PowerShell已经有一种简单的方法来返回输出以进行重定向: Write-Output

在Bash中,return退出一个函数,句点。

?? Bash累积输出相同:

hillr@Keith-Dell8500:~$ function foo() {
> echo "Hello"
> ls ~
> date
> return
> echo "World"
> }
hillr@Keith-Dell8500:~$ foo
Hello
bar.ps1  date.txt   test.ps1
baz.ps1  dotnet    powershell-preview_6.2.0-rc.1-1.ubuntu.16.04_amd64.deb
Tue Mar 26 16:06:18 DST 2019

就像PowerShell一样,Bash仍然输出从每个命令直到return语句的所有内容。

嗯,我想您是指$? 。 是的,那是一个差异。 我认为这些必须是Bash中的int返回值,以指示成功/失败。 在PS中, $?表示基于函数所产生的错误的成功/失败。 在实践中,我认为$?的使用并不多。 我通过try/catch/finally使用异常处理。

是。 return在这些语言中只有一个目的。 在PowerShell中,它与输出混合在一起。 混合返回值和输出流是一个坏主意。 它还可能导致类似内存泄漏的性能问题。 您真正想要的是协同例程或“收益率回报”,或生成器,生成器生成器和扫描器(如Icon中所示)。 原因是输入消耗是懒惰的,失败使计算暂停,同时允许丢弃到目前为止生成的部分计算。

您可以将“输出重定向”视为实际上两个对象:Processor和ProcessorContext。

编辑:我明白你为什么反对我的原初观点。 你以为我说的是屈服于输出是不好的。 相反,我是说以PowerShell的方式返回输出很不好。

我通过try/catch/finally使用异常处理。

键入很多,并且在所有情况下都没有明确表达意图。

好的,PowerShell基于垃圾收集的.NET,因此它不会遭受内存“泄漏”。 但这并不意味着您不能拥有一个存储库。 因此,在处理分配给变量或放入某种哈希表的大型输出/集合时,您必须格外小心。

我认为PowerShell的return语句应该只有一个目的,那就是尽早返回-没有别的。 当某人确实执行return 42它与$?没有关系。 它只是输出流中的另一项输出(屈服)。

就像我之前提到的, $?由PowerShell管理,与函数的输出/返回无关。 $?是根据产生的错误(或缺少错误)设置的。 这意味着当您执行$res = foo -$ res将包含函数foo输出的每个对象。 如果您想知道函数是否“失败”,可以在执行的每个命令上检查$? ,或者可以将一堆命令包装在try/catch块中。 我发现前者的键入要少得多(在脚本中)。

听到有人这样说,包括@BrucePay (请参阅下面的我的重点,引用他的话),但最重要的是:
在Korn Shell中,return退出一个函数,句点。
在Bash中,return退出一个函数,句点。

在PowerShell中,return也会退出函数:

PS C:\> function test { "hello"; return "!"; "world"}
PS C:\> test
hello
!

混合返回值和输出流是一个坏主意。 它还可能导致类似内存泄漏的性能问题

没有混淆,因为在PowerShell中输出流和返回值之间没有区别。 您在说好像该函数将字符串写入stdout并分别向调用方返回一个感叹号,但事实并非如此。 指向write-output似乎是同样的错误; 所有这些: write-output 'x''x'return 'x'沿着相同的输出路径向管道发送一些东西。 没有单独的返回值。

您真正想要的是协同例程或“收益率回报”,或生成器,生成器生成器和扫描器(如Icon中所示)。 Ť

这意味着,如果您在命令行上编写了命令,然后将其放在脚本或函数中,则其行为将有所不同:

PS C:\> robocopy /whatever
PS C:\> "robocopy /whatever" | set-content test.ps1; .\test.ps1
PS C:\> function test { robocopy /whatever }

我喜欢在所有三种情况下都看到相同的输出,而在两种情况下都不会吞下输出,因为我无缘无故地没有yield return 。 PowerShell的方法对于外壳程序和编写外壳程序/批处理脚本而言是一致且方便的-将您在命令行上编写的内容放到可以反复调用的位置。 这样做不应该完全改变代码的行为。

原因是输入消耗是懒惰的,失败使计算暂停,同时允许丢弃到目前为止生成的部分计算。

PowerShell管道由运行时控制,如果我理解您的意思,那么它已经能够做到:

PS D:\> 1..1mb |foreach { write-verbose -Verbose "incoming number: $_"; $_ } |select -first 3
VERBOSE: incoming number: 1
1
VERBOSE: incoming number: 2
2
VERBOSE: incoming number: 3
3

select将在有三件事时立即终止管道。其余的100万个数字未送入foreach 。 沿管道传输的信息是“推送”模型,但由PowerShell引擎控制。

虽然作为外壳程序,但是不清楚如果输入来自本机命令或PS cmdlet之外的内容,那么“输入中止计算失败”将意味着什么。

提供类似于Py文件编译为pyc文件以提高性能的“编译模块”。

我认为提高性能的预期解决方案是使用C#编写模块。 在某些情况下,PowerShell代码确实会编译JIT,但是PS团队成员在没有计划将其公开给最终用户进行自定义之前就说过,例如IIRC Dongbo Wang在PS Engine内部的PS Conf Asia演讲(2018年11月)。可能会改变)。

修复null重定向,以便将输出流重定向到null设备的三种不同方式在性能上相同。

理想,但似乎不太可能; $null = 4是一个简单的变量绑定, 4 | out-null需要启动管道和执行命令解析的开销-如果有人故意使out-null作为代理包装器并添加了日志记录,该怎么办?码? 那是技术债,要求运行管道和cmdlet比表达慢吗?

修正动态范围:

如果您的意思是“不使用动态范围”,那是一个有意的选择,例如Bruce Payette在这里说“动态范围,这几乎从未使用过;像30年前一样,LISP具有动态范围,但是很少使用现在,我们使用它的原因是:Shell使用的是Shell,Shell使用的是动态范围,甚至是Bash,Unix的Shell使用的是动态范围,即调用者上下文中的变量(在这种情况下)将调用者上下文中的变量复制到子上下文中[..]进行了一种修改,通常在动态作用域中,您查找调用链并将变量设置为存在,我们不这样做,我们设置变量在当前作用域中一直存在,并且再次模仿了shell的行为”。

那可能很烦人,但是对于外壳来说,这是“技术债务”吗?如果被更改,它将变成“ zeroTechnicalDebt”吗?

好的,PowerShell基于垃圾收集的.NET,因此它不会遭受内存“泄漏”。 但这并不意味着您不能拥有一个存储库。 因此,在处理分配给变量或放入某种哈希表的大型输出/集合时,您必须格外小心。

我有一位不是工程师的系统管理员,他写了一些逻辑来尝试对8 TB文件共享上所有文件的元数据进行制表。 这样做的结果并不理想:它占用了大量内存,并且还以100%cpu的速度固定了系统...在脚本启动后,我们甚至无法登录到该框中,这是在production_中保存服务器的唯一解决方案是要硬重启它。

以我的经验,PowerShell使编写此类垃圾变得容易。 您可以根据自己的意愿来处理并批评我的反馈。 它不会改变PowerShell使编写脚本有效地使生产机崩溃的事实。

@jzabroski可以分享脚本的任何详细信息吗?

Powershell人们试图鼓励管道流式传输( get-childitem | foreach-object {} ),而不是故意预先加载数据集( $files = get-childitem; $files | foreach-object )以减少内存使用。 它是否进行了前期加载?

是否使用Group-Object收集类似文件? 最近,组对象性能得到了改进,这将减少CPU使用量(如果不使用内存的话)。

PowerShell默认情况下为单核,其中是否包含作业/运行空间代码,是否为单核服务器? PS 6.1具有Start-ThreadJob ,它允许以较少的开销和节流的方式执行多个作业,以帮助控制CPU使用。

以我的经验,PowerShell使编写此类垃圾变得容易

所有告诉您编写$files = @(); $files += $f的教程和书籍都必须使全世界在cpu周期和内存上花费不菲。 这种模式很慢,处理器和内存昂贵,而且非常痛苦。 我很好奇这个模式是否在脚本中? (如果有什么办法,我们可以在不破坏向后兼容性的情况下阻止它,或者在以后的重大更改中使+ =在数组上无效?)。

但是,这里需要权衡。 Get-ChildItem -Recurse是22个字符,仅在我的C:驱动器上就吃掉800 + MB的RAM ,而无需使用大量内存行,并且根本不会获取文件元数据,并且更像是80MB。 这不是PS泄漏内存,而是PS使用它来获得用户便利。

您是否有任何语言不需要关心其工作原理的细节,可以编写有用的代码,可以不编写错误的代码以及不必成为熟练的程序员? (还有哪个外壳?)

您先前提出的任何更改都会使脚本起作用吗?

您可以编写一个Bash脚本来列出文件,为每个文件生成一个进程,直到服务器崩溃甚至您无法通过SSH进入。 您可以编写一个Python脚本,该脚本将os.walk() s放在文件树中,并为每个文件调用os.stat() ,并使用较少的内存并更快地完成-但是它需要10行而不是1行,因此您仍然需要注意操作系统并关心代码细节(它仍然不是外壳,并且不适用于PS Providers)。

我希望PS拥有更多的“成功秘诀”和更少的绊倒危险。 快速文件名列表是其中之一,我认为它很有用。 彻底地将其更改为完全不同的语言,并且在它擅长的领域中徘徊,是不会这样做的。

您想要的是Python,Python的存在,这是一种漂亮的语言,它不会因尝试适应两个不同的世界并保持来自不同OS(为什么是Microsoft)的三十年历史的Shell的作用域和函数返回语义而受到阻碍,或者是Microsoft的承诺向后兼容(以及对.Net的痴迷),因此它可以回避所有这些问题,而不是面对它们。

我希望PS拥有更多的“成功秘诀”和更少的绊倒危险。

如果我能为此增加二十个大拇指,我会的。 这正是PowerShell需要采用的模式和方法。

For-EachObject是一个PowerShell函数,用于获取PowerShell集合并将其转换为不可读的堆栈跟踪。

今天,我采用了Amazon编写的脚本来列出EC2 Windows磁盘: https: //docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ec2-windows-volumes.html#windows -list-disks

你猜怎么了? 我没有在此PC上进行Initialize-AWSDefaults设置,并且由于脚本作者使用了ForEach-Object,所以我的堆栈跟踪看起来像是_garbage_:

PS C:\Windows\system32> D:\Installs\PowerShell\List-EC2Disks.ps1
Could not access the AWS API, therefore, VolumeId is not available. 
Verify that you provided your access keys.
ForEach-Object : You cannot call a method on a null-valued expression.
At D:\Installs\PowerShell\List-EC2Disks.ps1:39 char:12
+ Get-disk | ForEach-Object {
+            ~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [ForEach-Object], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull,Microsoft.PowerShell.Commands.ForEachObjectCommand

每次人们在其代码中使用ForEach-Object表达式时,就会发生这种情况。 堆栈跟踪是“总是可怕的”。 重写这很痛苦。 幸运的是,这只是一个脚本,我将其复制粘贴到一个随机文件中,然后保存并运行。 如果在大型模块中有问题,我必须获取模块的源代码,重新编写脚本,希望上帝在重构它时,我没有通过转换ForEach-Object表达式破坏模块中的任何内容,并且希望我可以弄清楚REAL错误在哪里,所以我可以_做我的工作_。 现在,我从一些主要的存储库中派生了一些自定义代码,以弄清楚为什么会出错,因为与throw new Exception("message", ex) C#简单用法相比,PowerShell的Write-Error是AWFUL。

将其重写为使用for ($var in $list) ,将结果累积在变量$results ,我得到以下错误:

PS C:\Windows\system32> D:\Installs\PowerShell\List-EC2Disks.ps1
Could not access the AWS API, therefore, VolumeId is not available. 
Verify that you provided your access keys.
You cannot call a method on a null-valued expression.
At D:\Installs\PowerShell\List-EC2Disks.ps1:58 char:26
+ ... lDevice = If ($VirtualDeviceMap.ContainsKey($BlockDeviceName)) { $Vir ...
+                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

哦,顺便说一下,每次执行此操作时,我都不记得PowerShell将列表项添加到列表的愚蠢规则,所以我必须使用Google https://www.google.com/search?q=powershell+append + to +列出并阅读有关某人的博客文章,该文章解释了非直观的PowerShell列表操作的方式。

如果您不了解C#或出色的语言,则很容易就认为这种行为是可以的。 但是,C#通过将异常包装在AggregateException中来智能地处理了此问题,以便您同时获得内部和外部异常。 电源外壳? 哈哈哈哈是的,那太有用了。

@jzabroski可以分享脚本的任何详细信息吗?

可悲的是(_和幸福的_),我不记得了。 这是一个文件共享,因此几乎可以肯定最多是一个或两个核心。 如果是两个内核,则剩余的CPU可能是Windows Defender占用的。

编辑:在团队聊天中找到它。

$big32 = Get-ChildItem D:\Data\Website\Data -recurse | Sort-Object length -descending | select-object -first 32 | measure-object -property length –sum

另外,我刚刚和运行此命令的人交谈(感到非常糟糕),他说用例“是为了满足DFS的初始复制组大小要求而获取最大的32个文件”。

没有混淆,因为在PowerShell中输出流和返回值之间没有区别。

我还没有看到人们在第一次尝试中正确地使用它。 同样,这不是bash或其他任何shell所做的。 尽管将这两个概念统一是一个有趣的实验,但从可读性的角度来看,这是一场彻底而彻底的灾难。 在PowerShell v6中将Write-Output损坏了16个月并没有帮助。

@jzabroskiFor-EachObject输出中看来,您似乎没有使用Powershell Core(这是该存储库专用的),请尝试使用Powershell Core看看是否可以重现它。 确保使用最新版本。 请注意,Windows特定功能(例如Get-Disk)不是Powershell Core的一部分,在进行测试时,您需要考虑到这一点。

我还没有看到人们在第一次尝试中正确地使用它。 同样,这不是bash或其他任何shell所做的。

$ test () { ls /tmp; ls /etc/pm; return 5; ls /v*; } ; x=$(test)
$ echo "$x"
tmux-1000
sleep.d
$ echo $?
0

这都是在Bash函数中累积的两个独立命令的输出,并且Bash return在C#中不充当返回函数。 具体来说,“ Bash不是做什么”?

您没有正确捕获bash示例的返回值。 收益损失是因为美元? 始终是最后一条命令。 在你的情况下“回声”。

$ test () { ls /tmp; ls /etc/pm; return 5; ls /v*; } ; x=$(test)
$ echo $?
5
$ echo $x
tmux-1000
sleep.d

POWERSHELL的做法与此不同

> function test() { ls; return 5 ; ls } ; $x=test
> echo $?
True
> echo $x
    Directory: c:\foo\bar

Mode                LastWriteTime         Length Name
----                -------------         ------ ----

更多PowerShell奇特功能:

Chocolatey添加了一个RefreshEnv.cmd,它是一个GODSEND。 为什么不随PowerShell一起提供? 为什么我需要重新启动Shell或从Internet下载一些愚蠢的脚本来重置$ env?

@jzabroski这是在https://github.com/PowerShell/PowerShell-RFC/pull/92中提出的。

为PowerShell提供程序创建标准对象模型: https :

在有关SHiPS问题66的链接中,我概述了可能的候选cmdlet。 我不清楚为什么我们不能为这些核心cmdlet实现类似Haskell typeclass的行为。

该API已在PowerShell中。

@iSazonov您能否编辑和引用您要答复的内容,并添加一些上下文,例如指向所述API文档的超链接? TYVM

@jzabroski查找srcSystem.Management.Automationnamespaces文件夹中的文件。

POWERSHELL的做法与此不同

bash的处理方式有所不同- return只能设置(整数)进程退出代码(这不是“ return”在其他编程语言中的含义,即exit ) 。

PowerShell也可以做到这一点, exit 5

只是因为我们不是在PowerShell中使用退出代码(在计划任务中以及与其他OS的互操作中使用)非常频繁,因为它不是基于进程的Shell,并且不应退出函数。

归根结底,这是为什么检测stdout句柄类型在PowerShell中不起作用的原因(以及为什么“重定向”到out-null与强制转换为[void]或分配给的原因相同) $null

我建议人们提出新问题,如果他们确实有要采取行动的反馈意见-因为该团队已经明确明确地排除了PowerShell的不向后兼容版本,所以我不知道为什么这个线程会一直持续下去...

因为该团队已明确明确地排除了不兼容版本的

这对我来说是个新闻。 这怎么清楚? 请提供指向帖子或其他文档的链接。

对于我们中的某些人来说,听到“我们永远不会破坏兼容性”,而我们每天都在为某些断裂而苦恼,这有点令人沮丧。 该线程的目的是使思想的自由市场能够解决上游无法解决的一些问题。

有人可能会发现派发Powershell并创建技术负担最少的版本已经足够有利。 该小组将受益于本主题中提出的想法。 (这就是当今世界的运作方式。也许是最好的Powershell赢了。)

我要重申的是,该团队已经将Powershell的命令重命名为pwsh,从而产生了Powershell的“非后向兼容”版本。 Power(SHELL)是一个外壳。 外壳的工作就是成为将数字系统联系在一起的人类的粘合剂。 它不是具有最小外部依赖关系的已编译二进制文件。 甚至传统的编程语言都计划并做出重大更改。

POWERSHELL的做法与此不同

bash的执行方式有所不同- return只能设置(整数)进程退出代码(不是

我对其他贝壳很好奇。 他们在做什么? korn,csh等

这是一篇讨论多种语言的return语句的文章: https :

它指出操作系统[shell]允许返回多个内容:返回代码和输出。

尽管我们尽可能多地使用PowerShell 6,但我的团队拥有各种只能在PowerShell 5中运行的脚本。 以我的经验,PowerShell完全向后兼容的前提肯定是错误的。 至少有一些极端情况(例如: ErrorActionPreference行为不直观)绝对应该作为重大更改来解决-在这种情况下,解决该问题的可能性要小于不这样做的情况。

@chriskuech有一个问题,详细说明您与ErrorActionPreference

@ SteveL-MSFT我相信@KirkMunro直接链接到@chriskuech评论下方的

就是说, @ iSazonov在2018年10月1日关闭了https://github.com/PowerShell/PowerShell/issues/7774

看来这些东西不断以不同的形式出现,委员会一直在围绕它解决问题。

@jzabroski发现了我针对根本原因的主要问题。

过去,我也围绕以下症状之一提出了一个问题: Invoke-WebRequest引发终止错误。 我亲眼目睹了很多人对整个try / catch样板完全傻眼了,因为它们处理失败的HTTP请求,这是因为内部.NET方法引发终止错误。 在这三种不同的情况下,当我解释了潜在的行为以及据称永远无法解决该问题的原因时,工程师都会用粗话回应。

总而言之,终止错误会终止脚本,因为PowerShell创建者认为脚本在逻辑上不能超越错误进行操作,但是我认为,除脚本编写者根据具体情况做出决定外,这实际上不是任何人。 只有脚本编写者才能决定是否希望脚本执行StopSilentlyContinueContinue等。

(与上述问题有关)

如果PowerShell实现了选择加入的“ ZeroTechDebt”模式,则我绝对认为应该默认设置$ErrorActionPreference = "Stop" 。 显然,此设置在REPL中没有意义,因此不应在所有情况下默认设置,但实际上我的所有脚本均以$ErrorActionPreference = "Stop"为前缀,以启用“防御性编程”并表现为“正常” ”编程语言。

@chriskuech如果尚未使用,请看一下此RFC集合: https :

您还可以在该存储库的“问题”页面上的单独问题中找到四个RFC,如果它们更易于阅读/理解的话。 只需查找我发布的未解决问题,即可找到它们

@ SteveL-MSFT这是一个类似的问题,阻碍了我的工作效率。 不是$ErrorActionPreference而是$ConfirmPreference

下面是我编写的用于将SQL Server磁盘卷设置为64kb的丑陋脚本。

Import-Module Storage;

function Format-Drives
{
    # See https://stackoverflow.com/a/42621174/1040437 (Formatting a disk using PowerShell without prompting for confirmation)
    $currentconfirm = $ConfirmPreference
    $ConfirmPreference = 'none'

    Get-Disk | Where isOffline | Set-Disk -isOffline $false
    # The next line of this script is (almost) copy-pasted verbatim from: https://blogs.technet.microsoft.com/heyscriptingguy/2013/05/29/use-powershell-to-initialize-raw-disks-and-to-partition-and-format-volumes/
    Get-Disk | Where partitionstyle -eq 'raw' | Initialize-Disk -PartitionStyle MBR -Confirm:$false -PassThru | New-Partition -AssignDriveLetter -UseMaximumSize -IsActive | Format-Volume -FileSystem NTFS -AllocationUnitSize 64kb -Confirm:$false

    # See https://stackoverflow.com/a/42621174/1040437 (Formatting a disk using PowerShell without prompting for confirmation)
    $ConfirmPreference = $currentconfirm
}

Format-Drives

几点要点:

  1. Format-Volume的文档要求更多。 只有两个例子? 而且官方文档与网站不同步: https :
  2. 为什么我需要去StackOverflow学习如何避免使用脚本语言的GUI?
  3. 这很容易出错/很难“不加思索”地写,只是强调了诸如https://github.com/PowerShell/PowerShell-RFC/issues/198之类的相关问题-这是Bruce Payette在“只需输入您认为正确的内容,PowerShell In Action”就可以正常工作……完全是错误的。
  4. 另请参阅@ mklement0的问题: https :

需要-Version无法指定最大版本

请参阅: https :

当您编写加载.NET Framework库的高级函数时,这很烦人。在这些函数中,.NET Framework和.NET Core之间的API完全不同,例如AccessControl API的工作方式。

@jzabroski可以指定版本,但是要分开:

#requires -PSEdition Desktop
# versus
#requires -PSEdition Core

请快速注意一下, @ rjmholt已正式开始有关如何实施和管理重大更改的讨论:#13129。

另外,一旦允许重大更改,#6817和#10967是更多值得回顾的行为。
(它们具有相同的根本原因,请参见https://github.com/PowerShell/PowerShell/issues/10967#issuecomment-561843650)。

,+更强的事实是合乎逻辑的,因为PowerShell更注重列表而不是数字。 恕我直言。

@rjmholt已正式开始讨论

我应该说这比其他任何讨论都更加正式

我希望严格检查导入和函数签名的编辑时间。
您是否正在考虑引入诸如EcmaScript模块提供的新导入语义?
不再有全局名称空间污染。 导入机制缓慢。

此页面是否有帮助?
0 / 5 - 0 等级