【问题标题】:Powershell command not working: removing lines from file1 that are in file2Powershell命令不起作用:从file1中删除file2中的行
【发布时间】:2017-11-20 09:05:57
【问题描述】:

我正在使用以下代码从file1.txt 中删除file2.txt 中的行。

powershell -Command "$(Get-Content file1.txt) | Where-Object {$_ -notIn $(Get-Content file2.txt)}"

但是我收到一个关于 -notIn 的错误,正在寻找一个值表达式。但file2.txt 确实存在且不为空。

是什么导致了错误,如何解决?

【问题讨论】:

  • PowerShell 版本?
  • @PetSerAl 版本 2
  • -in-notin 是 v3+
  • @PetSerAl 谢谢。如果可能的话,我需要让它与默认安装的 Windows 7 Pro 兼容。

标签: windows file windows-7 powershell-2.0


【解决方案1】:

对于 PowerShell v2,反转参数并使用 -NotContains

powershell -Command "$(Get-Content file1.txt) | Where-Object {$(Get-Content file2.txt) -NotContains $_ }

Reference

【讨论】:

  • 谢谢!哪些 $ 是必要的,为什么? (如果你愿意,我可以问一个单独的问题。)
  • 只有$_ 是必需的,$ 前面的左括号不是必需的。
【解决方案2】:

补充LotPings' helpful answer

  • 为了执行速度,不要在每次循环迭代中执行Get-Content file2.txt - 预先缓存其结果。

  • 为了内存效率,在通过管道发送它们之前,不要将file1.txt 的所有行预先$(...) 一起收集。

因此(为简洁起见,我省略了 powershell -Command "..." 包装器):

$f2 = Get-Content file2.txt; Get-Content file1.txt | Where-Object { $f2 -NotContains $_ }

哪些 $ 是必需的,为什么?

(...)$(...)(子表达式运算符)和 @(...)数组子表达式运算符)所有收集整个命令的/命令的输出作为一个整体,在一个数组[System.Object[]])中,除非输出仅包含 1 个项目,其中返回该项目本身

需要

(...),只能包含单个命令或表达式:

  • 阐明表达式中的优先级,
  • 将命令(cmdlet/函数/外部实用程序调用)用作表达式的一部分。
  • 在管道中,您可以使用它事先强制收集封闭命令的整个输出,但这样做会抵消管道的内存限制优势。
    • 也就是说,使用 (Get-Content file) | ... | Set-Content file 之类的内容可以“就地”更新给定文件 file - 但请注意,这需要 file 的全部内容才能适应内存。
  • 除非您有如下所述的其他要求,否则首选(...) 而不是$(...)@(...)

$(...) 只需要:PetSerAl 致敬以寻求帮助。

  • 包含语句,例如ifforeach

  • 包含多个命令/表达式/语句

  • 将上述嵌入"..."(双引号字符串,其内容受插值(扩展)的影响)。
    在列出的运算符中,$(...)唯一可以(直接)嵌入双引号字符串中的运算符。

  • $(...) - 与(...) 不同 - 如果发生可能终止错误,则不会中止整个命令;例如:

    • 'hi' + $(1/0)"hi$(1/0)" 报告被零除错误,但仍然打印 hi;相比之下,'hi' + (1/0) 不会 - 除零错误会中止整个表达式。
    • 请注意,无条件终止错误甚至会中止任何包含$(...) 的表达式;例如,'hi' + $(Throw 'err')"hi$(Throw 'err')" 都只打印错误消息,而不是 hi

@(...) 只需要:

  • 确保命令的输出是一个数组,即使只返回1项;在其他方面,它的作用类似于$(),只是你不能在"..." 中使用它;有关@() 的详细讨论,请参阅我的this answer

  • 在 PSv3+ 中,标量和数组的统一处理通常使得 @(...) 不必要,但是 - 请参阅我的 this answer

【讨论】:

  • 哇!我正在仔细阅读你写的每一个字。谢谢!
  • 速度提高了大约 400%! :)
  • @PetSerAl:我明白你在说什么,但这不是真正的终止错误:例如,试试'hi' + $(throw "me")。诸如1/0 之类的表达式和诸如[int]::Parse('foo') 之类的.NET 方法调用占据了终止错误和非终止错误之间的奇怪中间地带。我个人的偏好:一定要让它们真正终止错误。同时:我们将这些在某些情况下终止的错误称为什么?
  • 我不确定你为什么调用 1/0 不是真正的终止错误,因为它们的行为与 cmdlet 调用 ThrowTerminatingError 方法完全一样:Add-Type 'using System.Management.Automation; [Cmdlet("Throw", "TerminatingError")] public class ThrowTerminatingErrorCmdlet : Cmdlet { protected override void EndProcessing() { ThrowTerminatingError(new ErrorRecord(new System.Exception(), "Error", ErrorCategory.NotSpecified, null)); } }' -PassThru | Select-Object -ExpandProperty Assembly | Import-Module
  • 还有(Write-Host Before)+(Throw-TerminatingError)+(Write-Host After); 'Next statement' vs (Write-Host Before)+(1/0)+(Write-Host After); 'Next statement',或者try { Write-Host Before; Throw-TerminatingError; Write-Host After } catch [int] { 'Error not handled so this is not printed' }; 'Next statement' vs try { Write-Host Before; 1/0; Write-Host After } catch [int] { 'Error not handled so this is not printed' }; 'Next statement'。恕我直言,throw 只是一个特例,它比标准终止错误更具终止性。
猜你喜欢
  • 2023-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-31
  • 2015-10-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多