linux 与 powershell 命令对照

一个常年混 Linux 的人第一次打开 Windows PowerShell,最容易犯的错是:把 ls -la 敲进去,然后疑惑为什么报错。本文用 5 个最高频的命令做切口,把「bash 思维」翻译成「PowerShell 思维」,最后说清楚 PowerShell 到底强在哪、又弱在哪。

阅读约定

  • Linux 侧以 bash + GNU coreutils 为准,示例环境为常见发行版(Ubuntu / CentOS 均可)。
  • Windows 侧标注了两个版本:Windows PowerShell 5.1(系统自带,基于 .NET Framework)与 PowerShell 7.x(pwsh,跨平台)。文中未特别说明处,两者行为一致。
  • 所有示例都可直接复制执行,涉及删除、停止进程的,建议先加 -WhatIf 预览。

目录

  1. 先理解一件事:管道里流的是什么
  2. 五组高频命令对照
  3. 其余常用命令映射表
  4. PowerShell 的十个优势
  5. 也必须说清的短板
  6. 怎么选:分工而不是站队
  7. 附录:一个真实场景的双写对比

先理解一件事:管道里流的是什么

这是两种 shell 的根本差异,理解了它,后面所有参数差异都不用死记。

bash 的管道传文本。 ps aux | grep nginx | awk '{print $2}' | xargs kill 能跑通,是因为每一步都在做同一件事:把上一段的字符串按空格、换行、冒号重新切分,取第 N 列。

PowerShell 的管道传对象。 Get-Process nginx | Stop-Process 中间没有任何解析动作——Get-Process 交出的是 System.Diagnostics.Process 对象,Stop-Process 直接读它的 Id 属性。

这带来两个直接后果:

  • bash 里 ps aux 换成 ps -ef,列的位置变了,awk '{print $2}' 立刻失效。
  • PowerShell 里属性有名字,$_.Id 永远是 Id,输出格式怎么变都不影响。
对比项 bash PowerShell
管道内容 文本流(byte/line) .NET 对象
取值方式 列号 + 正则 属性名
出错方式 静默取错列,结果错但不报错 属性不存在直接报错
组合成本 需要 awk/sed/cut 辅助 原生命令即可完成

五组高频命令对照

速查表

场景 Linux PowerShell 备注
列目录 ls Get-ChildItem ls/dir/gci 都是别名,但参数完全不同
切目录 cd Set-Location PowerShell 里还能 cd HKLM:\、cd Env:
文本搜索 grep Select-String 这个没有 grep 别名,习惯简写 sls
查进程 ps / top Get-Process ps 是别名,输出是对象不是表格
读文件 cat / tail Get-Content cat 是别名,-Tail -Wait 等于 tail -f

1. 列目录:ls → Get-ChildItem

Linux

ls -lah /var/log                # -l 长格式 -a 含隐藏 -h 人类可读
ls -lt | head -5                # 按修改时间倒序取前 5
find /var/log -name "*.log" -mtime -1   # 递归 + 时间过滤

常用参数:-a(隐藏文件)、-l(长格式)、-h(人类可读大小)、-t(按时间)、-S(按大小)、-R(递归)、-i(inode)。

PowerShell

Get-ChildItem C:\Logs -Filter *.log -Recurse -File |
  Sort-Object LastWriteTime -Descending |
  Select-Object -First 10 Name, Length, LastWriteTime

参数对照:

Linux PowerShell 说明
-a -Force 显示隐藏项
-R -Recurse 递归
-l 默认就是对象 无需长格式开关
-h 无 Length 是字节数,格式化交给 Format-Table

两个细节:

  • -Filter 由文件系统驱动过滤,比 -Include(PowerShell 自己筛)快一个数量级,能过滤就用它。
  • 输出是 FileInfo 对象,Length、LastWriteTime 都是强类型属性,可以直接参与计算和比较。

2. 切换目录:cd → Set-Location

Linux

cd /etc/nginx && ls
cd -                 # 回到上一个目录
pushd /tmp; popd     # 目录栈

PowerShell

Set-Location D:\Projects\api
Push-Location .\tests -PassThru
Pop-Location
Get-Location          # 等价于 pwd

cd HKLM:\SOFTWARE\Microsoft    # 注册表当目录浏览
cd Env:                        # 环境变量当目录浏览

cd 在 PowerShell 里不只是文件系统操作,它接受任意 PSDrive。注册表、证书存储、环境变量、函数、变量都能“进去看看”,这在排障时非常省事——比如 cd Env: 然后 dir 就是 env,cd Cert:\LocalMachine\My 就能列本机证书。

3. 文本搜索:grep → Select-String

Linux

grep -rn --include=*.py "TODO" ./src    # 递归 + 只看 .py
grep -c "ERROR" app.log                 # 只输出匹配行数
grep -A2 -B2 "panic" app.log            # 命中行前后各 2 行上下文
grep -v "DEBUG" app.log                 # 反向匹配

PowerShell

# 递归搜索:路径要靠 Get-ChildItem 提供
Get-ChildItem .\src -Recurse -Filter *.py | Select-String 'TODO'

# 单文件 + 上下文
Get-Content .\app.log | Select-String 'ERROR' -Context 2,2

# 纯文本匹配(不走正则),只取首个命中
Select-String -Path .\*.log -Pattern 'timeout' -SimpleMatch -List

参数对照:

grep Select-String 说明
-F -SimpleMatch 纯文本而非正则
-i 默认不区分大小写 反过来要 -CaseSensitive
-v -NotMatch 反向匹配
-A/-B n -Context n,m 前后行数
-l -List 只返回文件名
-o -AllMatches 取所有匹配(配合 .Matches)
-c (...).Count 或 Measure-Object 无直接等价参数

最容易踩的坑:Select-String -Path .\*.log 只匹配当前目录,不会递归。要递归得用 Get-ChildItem -Recurse -Filter *.log | Select-String 'ERROR';PowerShell 7 支持 .\**\*.log 递归通配,5.1 不支持。

4. 查进程:ps / top → Get-Process

Linux

ps aux | grep nginx
ps -ef --forest              # 进程树
top -o %MEM                  # 或 htop
pgrep -af "python.*api"      # 按命令行匹配并显示

PowerShell

# 内存占用 Top 5,顺手换算成 MB
Get-Process | Sort-Object WS -Descending | Select-Object -First 5 `
  Name, Id, @{n='MemMB'; e={[math]::Round($_.WS/1MB,1)}}

# 指定进程的关键属性
Get-Process -Name nginx | Select-Object Id, CPU, StartTime

# 等价于 ps aux 的“完整命令行”,Get-Process 默认不给
Get-CimInstance Win32_Process |
  Where-Object { $_.CommandLine -like '*api.exe*' } |
  Select-Object ProcessId, Name, CommandLine

三个细节:

  • Get-Process 默认拿不到完整命令行,需要 Get-CimInstance Win32_Process(或 PS7 的 -IncludeUserName 拿用户名,需管理员权限)。
  • 没有 top 那样的实时面板。要持续观察可以用 while ($true) { ... ; Start-Sleep 2 },或直接用 Get-Counter 读性能计数器。
  • 结束进程:Stop-Process -Name nginx ≈ pkill nginx;Stop-Process -Id 1234 -Force ≈ kill -9。

5. 读文件:cat / tail → Get-Content

Linux

cat -n app.log              # 带行号
tail -f -n 50 app.log       # 跟踪最后 50 行
head -20 config.yaml
wc -l app.log

PowerShell

Get-Content .\app.log -Tail 50 -Wait     # 等价 tail -f -n 50
Get-Content .\app.log -TotalCount 20     # 等价 head -20
(Get-Content .\app.log).Count            # 等价 wc -l

# 解析 JSON 必须加 -Raw,否则按行返回字符串数组会报错
Get-Content .\config.json -Raw | ConvertFrom-Json

参数对照:-Tail n、-Head n(PS 3.0+)、-Wait(跟踪追加)、-Raw(整体读成单个字符串)、-TotalCount、-Encoding(中文乱码就靠它)。

-Encoding 这个参数值得单独说一句:Windows 上大量历史文件是 GBK/GB2312,Get-Content .\old.log -Encoding Default 才读得对,默认 UTF-8 会出乱码。

其余常用命令映射表

Linux PowerShell 说明
rm -rf Remove-Item -Recurse -Force 破坏性操作,先加 -WhatIf
cp -r Copy-Item -Recurse
mv Move-Item
mkdir -p New-Item -ItemType Directory -Force
touch New-Item -ItemType File
man xxx Get-Help xxx -Examples 功能更结构化,-Online 还能开浏览器
which / type Get-Command xxx 能查到来自哪个模块
kill -9 Stop-Process -Id 123 -Force
df -h Get-PSDrive -PSProvider FileSystem 或 Get-Volume
du -sh Get-ChildItem -Recurse | Measure-Object Length -Sum
systemctl status Get-Service xxx 启停用 Start-Service/Stop-Service
env Get-ChildItem Env: 读取变量 $env:PATH
echo Write-Output 默认输出对象,非字符串
history Get-History
wc -l Measure-Object -Line
sort / uniq Sort-Object / Sort-Object -Unique
curl Invoke-RestMethod PS7 里 curl 是原生 curl.exe,5.1 里是别名
chmod icacls / Set-Acl ACL 模型不同,无法一一对应
awk '{print $3}' Select-Object 属性名 按名字取值,不用数列号
xargs ForEach-Object
sudo Start-Process -Verb RunAs

PowerShell 的十个优势

1. 对象管道,免除文本解析

Get-Process | Where-Object CPU -gt 100 | Stop-Process

没有 awk、没有列号、没有正则。命令怎么写,取决于对象的属性名,而不取决于输出格式。

2. 可直接调用整个 .NET 生态

[IO.Compression.ZipFile]::CreateFromDirectory('D:\data', 'D:\data.zip')

一行完成压缩。bash 得先确认装了 zip,再拼参数、处理空格路径。

3. 命名一致,且能自我解释

动词-名词 结构(Get/Set/New/Remove/Copy/Start/Stop),参数用 -Name 而非 -n。配合三个自省命令,不联网也能学会:

Get-Command *service*      # 有哪些相关命令
Get-Help Get-Service -Examples
Get-Process | Get-Member   # 这个对象有哪些属性和方法

4. 通用参数让破坏性操作变安全

参数 作用
-WhatIf 只打印“将要做什么”,不真执行
-Confirm 逐条确认
-Verbose 输出详细过程
-ErrorAction Stop 把非终止错误升级为异常,配合 try/catch
-OutVariable 保留输出供后续使用

批量删文件前先跑一遍 Remove-Item ... -WhatIf,是 PowerShell 里最划算的习惯。

5. Windows 系统管理是真·第一等公民

注册表、证书、环境变量、服务、事件日志、WMI/CIM、Hyper-V、AD、Exchange、Azure,都有官方模块。这是 bash 在 Windows 上做不到的:

Get-WinEvent -LogName System -MaxEvents 20 |
  Where-Object LevelDisplayName -eq 'Error'

6. 结构化输出,天生适合做接口

Get-Process | Select-Object Name, Id, WS |
  Export-Csv .\procs.csv -NoTypeInformation -Encoding UTF8

Get-Service | ConvertTo-Json -Depth 3 | Out-File services.json

ConvertTo-Json / ConvertFrom-Json / Export-Csv / Export-Clixml 一行得到机器可读结果。

7. 跨平台 + 远程批量

PowerShell 7(pwsh)在 Linux 和 macOS 上同样能跑;Invoke-Command -ComputerName 批量下发到多台主机,PS7 还支持基于 SSH 的远程,可以统一管 Linux 服务器。

8. 具备工程化能力

try/catch/finally 是真正的异常处理;支持类、模块、Pester 单元测试、PSGallery 包管理。脚本超过 200 行时,这个差距会非常明显——bash 到这个体量就开始难维护了。

9. 原生并行

1..10 | ForEach-Object -Parallel {
    "task $_ on $using:PWD"
} -ThrottleLimit 5

10. 安全与合规

执行策略(ExecutionPolicy)、脚本签名、Constrained Language Mode、脚本块日志、转录(transcript),企业环境可审计、可追责。

也必须说清的短板

只讲优点是不负责任的,几个真实的痛点:

  • 冷启动慢。pwsh -c "..." 几百毫秒起步,临时小任务远不如 bash 利落。
  • 命令冗长。Get-ChildItem -Recurse -Force 就是比 ls -laR 长,虽然有别名和 Tab 补全,但写脚本时依然啰嗦。
  • 纯文本处理反而弱。列切分、正则替换这类活,sed/awk/cut 的组合更顺手,PowerShell 要靠 -split、-replace、ForEach-Object 硬拼。
  • 版本分裂。Windows PowerShell 5.1 与 PowerShell 7 并存,部分模块只在 Windows 上跑,跨平台时得先确认目标环境。
  • 资料生态偏向 bash。网上搜到的答案九成是 bash,移植需要翻译成本。

怎么选:分工而不是站队

  • Windows 本机运维、批量文件处理、系统配置、跨服务编排 → PowerShell。它的对象模型和系统集成度在这里无可替代。
  • 跨平台 CI、容器内、纯文本流处理 → bash。启动快、环境通用、工具链成熟。
  • 两者可以互相调用:Windows 上 wsl 进 bash,Linux 上装 pwsh 跑 PowerShell 脚本。没有必要二选一。

附录:一个真实场景的双写对比

需求:找出最近 24 小时内修改过的 .log 文件,统计每个文件中 ERROR 的条数,取前 5 名。

bash

find /var/log -name "*.log" -mtime -1 -print0 \
  | xargs -0 grep -c "ERROR" 2>/dev/null \
  | sort -t: -k2 -nr \
  | head -5

要点:-print0 + xargs -0 是为了处理带空格的路径;sort -t: -k2 -nr 按冒号切分、按第 2 列数字倒序。

PowerShell

Get-ChildItem C:\Logs -Filter *.log -Recurse -File |
  Where-Object LastWriteTime -gt (Get-Date).AddDays(-1) |
  ForEach-Object {
    [pscustomobject]@{
      File  = $_.FullName
      Count = (Select-String -Path $_.FullName -Pattern 'ERROR' -AllMatches).Matches.Count
    }
  } |
  Sort-Object Count -Descending |
  Select-Object -First 5

要点:[pscustomobject]@{} 现场构造结构化结果;路径带空格不需要任何特殊处理;结果直接可以 Export-Csv 或 ConvertTo-Json 交给下游。

同一件事,bash 靠管道拼装、依赖字段位置;PowerShell 靠对象变换、依赖属性名。哪种更好取决于你要不要一个“能继续被程序消费”的结果——这也是两者设计哲学最直观的地方。


写在最后:如果你刚从一个环境切到另一个,别急着找“等价命令表”,先问一句“这条管道里流的是什么”。想通这一点,剩下的查文档就行。

本文示例在 Windows PowerShell 5.1、PowerShell 7.4、bash 5.x 上验证。

posted @ 2026-10-31 20:21  孤独的小苗  阅读(5)  评论(0)    收藏  举报