PowerShell 管道和过滤

PowerShell 的管道(Pipeline)和过滤是 PowerShell 最强大、最核心的功能之一,几乎所有高级脚本都离不开它们。下面系统性地讲解管道原理和各种过滤方式。

1. PowerShell 管道的核心机制(和其他壳的巨大区别)

项目PowerShell 管道Linux Bash / cmd 管道
传递的内容对象(.NET Object)纯文本(string)
管道符号||
左边命令输出完整的对象(含属性和方法)只剩 ToString() 后的文本
右边命令接收参数自动按属性绑定(ByPropertyName)只能从 stdin 读文本

例子:

# 这条命令输出的不是文本,而是 Process 对象
Get-Process | Where-Object {$_.CPU -gt 100}

# Linux 等价写法必须用文本解析,极其脆弱
ps -aux | grep chrome | awk '{if($3>10) print}'

2. 管道中常见的过滤命令(性能从高到低排序)

命令推荐场景性能特点例子
Where-Object (过滤位置)强烈推荐,只要能用就用这个在管道最左边过滤,性能最高Get-Process
Select-Object -First/-Last/-Skip取前N条、后N条、跳过前N条也是流式处理,性能极高Get-ChildItem
Where-Object (普通)复杂条件,无法用参数过滤时使用每条记录都进入管道,性能中等Get-Service
ForEach-Object需要对每条记录做复杂操作或副作用性能较差,避免在超大集合中使用Get-ChildItem
.Where() 方法 (PowerShell 7+)最现代、最快的过滤方式比 Where-Object 快 5-50 倍(Get-Process).Where{$_.CPU -gt 100}
.Where() 加速模式超大数据集推荐极快,支持 Acceleration(Get-EventLog -LogName System -Newest 100000).Where({$_.EntryType -eq ‘Error’}, ‘Split’)

3. 最佳实践:尽可能用“参数过滤”而不是管道过滤

很多 cmdlet 支持直接在参数层面过滤,比管道快几十到几百倍!

# 慢(读取所有进程再过滤)
Get-Process | Where-Object Name -eq "chrome"

# 快(只返回 chrome 进程,推荐!)
Get-Process -Name chrome

# 更多例子
Get-Service -Name w*                  # 比 Get-Service | Where Name -like "w*" 快很多
Get-ChildItem -Path C:\ -Recurse -File -Filter "*.log"   # -Filter 是提供者级过滤,最快
Get-EventLog -LogName System -EntryType Error           # 直接过滤
Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4624} -MaxEvents 100  # 最快方式

4. 实战常用的管道过滤组合

# 1. 找出占用 CPU 前 10 的进程(经典)
Get-Process | Sort-Object CPU -Descending | Select-Object -First 10

# 2. 找出最近 3 天修改的 .log 文件并按大小倒序
Get-ChildItem D:\Logs -Recurse -File -Filter "*.log" | 
  Where-Object LastWriteTime -gt (Get-Date).AddDays(-3) | 
  Sort-Object Length -Descending

# 3. PowerShell 7+ 推荐写法(更快、更清晰)
(Get-ChildItem D:\Logs -Recurse -File).Where{
    $_.Extension -eq '.log' -and $_.LastWriteTime -gt (Get-Date).AddDays(-3)
} | Sort-Object Length -Descending | Select-Object -First 20

# 4. 只显示错误事件的前 50 条(加速模式)
(Get-EventLog System -ErrorAction SilentlyContinue).Where(
    {$_.EntryType -eq 'Error'}, 'First', 50
)

5. 管道链性能优化黄金法则(记住这几条就够了)

  1. 越左边过滤越好(让管道尽早变小)
  2. 优先使用 cmdlet 的参数过滤(-Name, -Filter, -Include 等)
  3. 用 Where-Object 放在管道最前面,而不是最后
  4. 大集合用 .Where() 方法(PS 7+)
  5. 避免在管道里用 ForEach-Object 做简单过滤,改用 Where-Object
  6. 需要 Select-Object 时尽早放(减少后面传递的属性量)

6. 一条终极性能对比(10万条数据)

# 慢 100倍(3-8秒)
1..100000 | ForEach-Object { $_ % 100 -eq 0 }

# 中等(0.3-0.8秒)
1..100000 | Where-Object { $_ % 100 -eq 0 }

# 最快(0.03-0.06秒,PS7+)
(1..100000).Where{ $_ % 100 -eq 0 }

掌握了上面这些,你写出来的 PowerShell 脚本既优雅又飞快。有什么具体场景需要优化管道,欢迎贴代码,我帮你改得更快!

文章已创建 2965

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部