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预览。
目录
- 先理解一件事:管道里流的是什么
- 五组高频命令对照
- 其余常用命令映射表
- PowerShell 的十个优势
- 也必须说清的短板
- 怎么选:分工而不是站队
- 附录:一个真实场景的双写对比
先理解一件事:管道里流的是什么
这是两种 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 上验证。

浙公网安备 33010602011771号