CMD、PowerShell 与 Bash 命令对照表
同一任务在命令提示符、PowerShell 和 bash 中的写法并排对照:文件、grep、环境变量、进程、网络、服务和脚本编写。
最后核对:2026-10-18,依据 Microsoft Learn 上的 PowerShell 7.6 和 Windows PowerShell 5.1 参考、Windows 命令参考以及 GNU Bash 5.2 手册。
文件和文件夹
| 任务 | CMD(命令提示符) | PowerShell | Bash(Linux/macOS) |
|---|---|---|---|
| 列出文件 # PowerShell 别名:gci、dir,在 Windows 上还有 ls。 | dir | Get-ChildItem | ls -l |
| 递归列出所有文件 # | dir /s /b | Get-ChildItem -Recurse -File | find . -type f |
| 显示当前目录 # 在 CMD 中,不带参数的 cd 会输出当前目录。PowerShell 别名:pwd、gl;也可用 $PWD 变量。 | cd | Get-Location | pwd |
| 切换目录 # CMD 需要加 /d 才能同时切换驱动器和文件夹。PowerShell 别名:cd、sl、chdir。 | cd /d D:\work | Set-Location D:\work | cd /home/me/work |
| 转到主目录 # | cd %USERPROFILE% | Set-Location ~ | cd ~ |
| 创建文件夹(含父级) # 启用命令扩展时(默认启用),CMD 的 mkdir 会创建中间文件夹。在 PowerShell 中,mkdir 是封装了 New-Item -ItemType Directory 的函数。 | mkdir a\b\c | New-Item -ItemType Directory -Path a\b\c | mkdir -p a/b/c |
| 创建空文件 # | type nul > file.txt | New-Item file.txt | touch file.txt |
| 复制文件 # | copy src.txt dst.txt | Copy-Item src.txt dst.txt | cp src.txt dst.txt |
| 递归复制文件夹 # xcopy src dst /E /I 也可以;robocopy 是官方支持的工具,可断点续传和重试。 | robocopy src dst /E | Copy-Item src dst -Recurse | cp -r src dst |
| 完全镜像文件夹 危险 # 危险: 两者都会删除目标中源里没有的文件。把两个路径写反会清空你本想保留的文件夹。robocopy /L 和 rsync -n 可以试运行。 | robocopy src dst /MIR | (no cmdlet; call robocopy) | rsync -a --delete src/ dst/ |
| 移动文件 # | move a.txt archive\ | Move-Item a.txt archive\ | mv a.txt archive/ |
| 重命名文件 # | ren old.txt new.txt | Rename-Item old.txt new.txt | mv old.txt new.txt |
| 删除文件 # | del file.txt | Remove-Item file.txt | rm file.txt |
| 删除文件夹及其内容 危险 # 危险: 不经过回收站,使用 /q、-Force 或 -f 时也不会提示。请先检查路径;在 PowerShell 中加 -WhatIf 可查看将删除哪些内容。 | rmdir /s /q folder | Remove-Item folder -Recurse -Force | rm -rf folder |
| 创建符号链接 # 在 Windows 上,除非开启了开发者模式,否则创建符号链接需要管理员提示符。注意参数顺序:CMD/PowerShell 中链接在前,ln 中目标在前。 | mklink link.txt target.txt
mklink /D linkdir targetdir | New-Item -ItemType SymbolicLink -Path link.txt -Target target.txt | ln -s target.txt link.txt |
| 更改文件权限 # Windows 使用 ACL,而不是 rwx 权限位;icacls 通常比 Set-Acl 更简单。 | icacls file.txt /grant alice:F | Get-Acl / Set-Acl | chmod 644 file.txt |
| 文件校验和(SHA-256) # Get-FileHash 默认使用 SHA256;其他算法用 -Algorithm MD5 或 SHA1。macOS:shasum -a 256。 | certutil -hashfile file.iso SHA256 | Get-FileHash file.iso | sha256sum file.iso |
| 创建 zip 文件 # Windows 10 1803 及更高版本自带 tar.exe(bsdtar);-a 会根据 .zip 扩展名选择格式。 | tar -a -c -f out.zip folder | Compress-Archive -Path folder -DestinationPath out.zip | zip -r out.zip folder |
| 解压 zip 文件 # | tar -xf out.zip | Expand-Archive out.zip -DestinationPath dest | unzip out.zip -d dest |
读写文件内容
| 任务 | CMD(命令提示符) | PowerShell | Bash(Linux/macOS) |
|---|---|---|---|
| 输出文件内容 # PowerShell 别名:gc、type,在 Windows 上还有 cat。 | type file.txt | Get-Content file.txt | cat file.txt |
| 分页查看文件 # | more file.txt | Get-Content file.txt | Out-Host -Paging | less file.txt |
| 前 10 行 # -Head 是 -TotalCount 的别名。 | 无内置命令 | Get-Content file.txt -TotalCount 10 | head -n 10 file.txt |
| 最后 10 行 # | 无内置命令 | Get-Content file.txt -Tail 10 | tail -n 10 file.txt |
| 实时跟踪日志文件 # | 无内置命令 | Get-Content app.log -Tail 10 -Wait | tail -f app.log |
| 将文本写入文件(覆盖) # 在 CMD 中,> 前面的空格会被写入文件。在 Windows PowerShell 5.1 中,> 写入 UTF-16 LE;PowerShell 7 写入不带 BOM 的 UTF-8。Set-Content -Encoding utf8 在两者中都能明确指定编码。 | echo hello> file.txt | 'hello' | Set-Content file.txt | echo hello > file.txt |
| 向文件追加文本 # | echo hello>> file.txt | Add-Content file.txt 'hello' | echo hello >> file.txt |
| 统计行数 # | find /c /v "" file.txt | (Get-Content file.txt).Count | wc -l file.txt |
| 比较两个文件 # 在 Windows 上的 PowerShell 中,diff 是 Compare-Object 的别名,而不是文本比较。 | fc a.txt b.txt | Compare-Object (Get-Content a.txt) (Get-Content b.txt) | diff a.txt b.txt |
| 排序行 # | sort file.txt | Get-Content file.txt | Sort-Object | sort file.txt |
| 去除重复行 # | 无内置命令 | Get-Content file.txt | Sort-Object -Unique | sort -u file.txt |
| 替换文件中的文本 # -replace 使用正则表达式;括号会在 Set-Content 重新打开文件之前读完整个文件。macOS 的 sed 需要写 -i ''。 | 无内置命令 | (Get-Content f.txt) -replace 'old','new' | Set-Content f.txt | sed -i 's/old/new/g' f.txt |
搜索(grep 的替代命令)
| 任务 | CMD(命令提示符) | PowerShell | Bash(Linux/macOS) |
|---|---|---|---|
| 在文件中查找文本 # Select-String 默认不区分大小写(用 -CaseSensitive 更改)。搜索子文件夹:Get-ChildItem -Recurse -Filter *.log | Select-String error。 | findstr /s /i /n "error" *.log | Select-String -Path *.log -Pattern error | grep -rin 'error' --include='*.log' . |
| 筛选命令输出 # | ipconfig | findstr IPv4 | ipconfig | Select-String IPv4 | ip a | grep inet |
| 不匹配的行 # | findstr /v "DEBUG" app.log | Select-String -Path app.log -Pattern DEBUG -NotMatch | grep -v DEBUG app.log |
| 用正则表达式搜索 # findstr 只支持一小部分正则语法(没有 |,没有 {n})。Select-String 使用 .NET 正则表达式。 | findstr /r "^ERR.*timeout" app.log | Select-String -Path app.log -Pattern '^ERR.*timeout' | grep -E '^ERR.*timeout' app.log |
| 按名称查找文件 # | dir /s /b *.log | Get-ChildItem -Recurse -Filter *.log | find . -name '*.log' |
| 查找程序所在位置 # 在 PowerShell 中,where 是 Where-Object 的别名;输入 where.exe 才能使用 CMD 工具。 | where git | Get-Command git | command -v git |
环境变量
| 任务 | CMD(命令提示符) | PowerShell | Bash(Linux/macOS) |
|---|---|---|---|
| 列出所有变量 # | set | Get-ChildItem Env: | env |
| 读取变量 # | echo %PATH% | $env:PATH | echo "$PATH" |
| 为当前会话设置 # CMD:= 两边不能有空格,否则空格会成为名称和值的一部分。 | set MY_VAR=hello | $env:MY_VAR = 'hello' | export MY_VAR=hello |
| 永久设置(当前用户) # setx 和 SetEnvironmentVariable 只对新窗口生效,对当前窗口无效。setx 会截断超过 1024 个字符的值,所以不要用它修改 PATH。 | setx MY_VAR hello | [Environment]::SetEnvironmentVariable('MY_VAR','hello','User') | echo 'export MY_VAR=hello' >> ~/.bashrc |
| 删除变量 # | set MY_VAR= | Remove-Item Env:MY_VAR | unset MY_VAR |
| 将文件夹添加到 PATH(当前会话) # Linux/macOS 上的 PowerShell 7 用 : 而不是 ; 分隔 PATH。[IO.Path]::PathSeparator 会给出正确的分隔符。 | set PATH=%PATH%;C:\tools | $env:PATH += ';C:\tools' | export PATH="$PATH:/opt/tools" |
| 仅对一条命令设置 # | 无内置命令 | $env:DEBUG = '1'; ./app; Remove-Item Env:DEBUG | DEBUG=1 ./app |
进程
| 任务 | CMD(命令提示符) | PowerShell | Bash(Linux/macOS) |
|---|---|---|---|
| 列出进程 # | tasklist | Get-Process | ps aux |
| 按名称查找进程 # | tasklist /FI "IMAGENAME eq chrome.exe" | Get-Process chrome | pgrep -a chrome |
| 按进程 ID 结束进程 # 不加 /F 或 -Force 时,Windows 会请求进程自行关闭。kill 发送 SIGTERM;kill -9 强制结束。 | taskkill /PID 1234 /F | Stop-Process -Id 1234 -Force | kill 1234 |
| 按名称结束进程 # | taskkill /IM notepad.exe /F | Stop-Process -Name notepad | pkill notepad |
| 启动程序 # start 中的空 "" 是窗口标题;没有它的话,带引号的程序路径会被当作标题。 | start "" notepad.exe | Start-Process notepad | gedit & |
| 以提升权限运行(管理员/root) # Windows PowerShell 5.1 请用 powershell 代替 pwsh。Windows 11 24H2 及更高版本还可以在“设置”中启用内置的 sudo 命令。 | runas /user:Administrator cmd | Start-Process pwsh -Verb RunAs | sudo command |
| CPU 占用前 10 的进程 # Get-Process 中的 CPU 是启动以来累计的处理器秒数,而不是当前百分比。 | 无内置命令 | Get-Process | Sort-Object CPU -Descending | Select-Object -First 10 | ps aux --sort=-%cpu | head |
| 查看占用端口的程序 # Get-NetTCPConnection 仅限 Windows。netstat -ano 的最后一列是 PID:用 tasklist /FI "PID eq 1234" 查询。 | netstat -ano | findstr :8080 | Get-NetTCPConnection -LocalPort 8080 | sudo ss -ltnp | grep :8080 |
网络
| 任务 | CMD(命令提示符) | PowerShell | Bash(Linux/macOS) |
|---|---|---|---|
| 显示 IP 地址 # Get-NetIPAddress 和其他 Net* cmdlet 仅限 Windows(NetTCPIP 模块)。 | ipconfig /all | Get-NetIPAddress | ip addr |
| Ping 主机 # Windows 的 ping 默认发送 4 次后停止;Linux 的 ping 会一直运行到按 Ctrl+C。 | ping -n 4 example.com | Test-Connection example.com -Count 4 | ping -c 4 example.com |
| 测试 TCP 端口 # Test-NetConnection 仅限 Windows。在 PowerShell 7 中:Test-Connection example.com -TcpPort 443。 | 无内置命令 | Test-NetConnection example.com -Port 443 | nc -zv example.com 443 |
| DNS 查询 # Resolve-DnsName 仅限 Windows;三者都有 nslookup。 | nslookup example.com | Resolve-DnsName example.com | dig example.com |
| 路由跟踪 # | tracert example.com | Test-NetConnection example.com -TraceRoute | traceroute example.com |
| 清除 DNS 缓存 # bash 这一行适用于使用 systemd-resolved 的系统。 | ipconfig /flushdns | Clear-DnsClientCache | sudo resolvectl flush-caches |
| HTTP GET(API 调用) # Invoke-RestMethod 会把 JSON 解析为对象;Invoke-WebRequest 返回状态码、标头和原始内容。 | curl.exe https://api.example.com/items | Invoke-RestMethod https://api.example.com/items | curl https://api.example.com/items |
| 下载文件 # Windows 10 1803 及更高版本自带 curl.exe。在 Windows PowerShell 5.1 中,如果机器未设置 Internet Explorer,请为 Invoke-WebRequest 加上 -UseBasicParsing。 | curl.exe -L -o file.zip https://example.com/file.zip | Invoke-WebRequest https://example.com/file.zip -OutFile file.zip | curl -LO https://example.com/file.zip |
| POST JSON # CMD 没有单引号,所以 curl.exe 的内部双引号要用反斜杠转义。 | curl.exe -X POST -H "Content-Type: application/json" -d "{\"a\":1}" https://api.example.com | Invoke-RestMethod https://api.example.com -Method Post -ContentType 'application/json' -Body (@{a=1} | ConvertTo-Json) | curl -X POST -H 'Content-Type: application/json' -d '{"a":1}' https://api.example.com |
| SSH 连接服务器 # Windows 10 1809+ 和 Windows 11 默认已安装 OpenSSH 客户端。 | ssh user@host | ssh user@host | ssh user@host |
服务和系统
| 任务 | CMD(命令提示符) | PowerShell | Bash(Linux/macOS) |
|---|---|---|---|
| 列出服务 # 在 Windows PowerShell 5.1 中,sc 是 Set-Content 的别名:请输入 sc.exe。PowerShell 6+ 已删除该别名。 | sc query | Get-Service | systemctl list-units --type=service |
| 服务状态 # | sc query Spooler | Get-Service Spooler | systemctl status nginx |
| 启动 / 停止服务 # | net start Spooler
net stop Spooler | Start-Service Spooler
Stop-Service Spooler | sudo systemctl start nginx
sudo systemctl stop nginx |
| 重启服务 # | net stop Spooler && net start Spooler | Restart-Service Spooler | sudo systemctl restart nginx |
| 开机自启 # sc.exe 要求 start= 后面有空格,前面没有空格。 | sc config Spooler start= auto | Set-Service Spooler -StartupType Automatic | sudo systemctl enable nginx |
| 操作系统和硬件信息 # | systeminfo | Get-ComputerInfo | uname -a; cat /etc/os-release |
| 计算机名 # | hostname | $env:COMPUTERNAME | hostname |
| 当前用户 # 在 Windows 上的 PowerShell 中也可用 $env:USERNAME。 | whoami | whoami | whoami |
| 磁盘可用空间 # 较旧的 Windows 版本运行 fsutil 需要管理员提示符。Get-Volume(仅限 Windows)也会显示容量和可用空间。 | fsutil volume diskfree C: | Get-PSDrive -PSProvider FileSystem | df -h |
| 运行时间 # Get-Uptime 需要 PowerShell 6+。在 5.1 中:(Get-Date) - (Get-CimInstance Win32_OperatingSystem).LastBootUpTime。 | systeminfo | find "Boot Time" | Get-Uptime | uptime |
| 立即重启 # | shutdown /r /t 0 | Restart-Computer | sudo reboot |
| 清屏 # 在 Windows 上的 PowerShell 中,cls 和 clear 都能用。 | cls | Clear-Host | clear |
| 命令历史 # Get-History 只包含当前会话。PSReadLine 会把更早的历史保存在 (Get-PSReadLineOption).HistorySavePath 文件中;三个 Shell 都可以用 Ctrl+R 搜索历史。 | doskey /history | Get-History | history |
| 查看命令帮助 # 运行一次 Update-Help(5.1 中需管理员权限)即可下载完整的 PowerShell 帮助。 | dir /? | Get-Help Get-ChildItem -Examples | man ls |
| 当前日期 # %date% 遵循本机的区域格式,因此解析它的脚本换个区域设置就会出错。 | echo %date% | Get-Date -Format 'yyyy-MM-dd' | date +%F |
| 等待 5 秒 # | timeout /t 5 | Start-Sleep -Seconds 5 | sleep 5 |
| 将输出复制到剪贴板 # macOS:pbcopy。Wayland:wl-copy。在 PowerShell 中用 Get-Clipboard 读取。 | dir | clip | Get-ChildItem -Name | Set-Clipboard | ls | xclip -selection clipboard |
管道传递对象与文本
| 任务 | CMD(命令提示符) | PowerShell | Bash(Linux/macOS) |
|---|---|---|---|
| 选取列 / 属性 # PowerShell 的管道传递的是 .NET 对象,因此直接按名称选择属性,而不用解析列。 | 无内置命令 | Get-Process | Select-Object Name, Id, WS | ps -eo comm,pid,rss |
| 按值筛选行 # PowerShell 能识别 500MB、1GB 这样的字面量。awk 比较的是第 6 列(RSS,单位 KB)。 | tasklist | findstr chrome | Get-Process | Where-Object WS -gt 500MB | ps aux | awk '$6 > 500000' |
| 对每一项执行操作 # $_(或 $PSItem)表示当前对象。在 .bat 文件中要写 %%f 而不是 %f。 | for %f in (*.txt) do echo %f | Get-ChildItem *.txt | ForEach-Object { $_.Name } | for f in *.txt; do echo "$f"; done |
| 查看对象有哪些属性 # PowerShell 中最有用的探索命令;也可试试 | Format-List *。 | 无内置命令 | Get-Process | Get-Member | 无内置命令 |
| 解析 JSON # 使用 -Raw 让文件作为一个字符串读入;输出时用 ConvertTo-Json -Depth 10(默认深度为 2)。 | 无内置命令 | Get-Content data.json -Raw | ConvertFrom-Json | jq . data.json |
| 读取并筛选 CSV # Import-Csv 读取的值都是字符串;数值比较时要用 [int] 转换。 | 无内置命令 | Import-Csv users.csv | Where-Object { [int]$_.Age -gt 30 } | awk -F, 'NR>1 && $3 > 30' users.csv |
| 导出为 CSV # -NoTypeInformation 在 PowerShell 6+ 中是默认行为,但在 5.1 中需要手动加上。 | 无内置命令 | Get-Process | Export-Csv procs.csv -NoTypeInformation | ps -eo pid,comm --no-headers | awk '{print $1","$2}' > procs.csv |
| 计数、求和、平均值 # | find /c /v "" file.txt | Get-ChildItem -File | Measure-Object Length -Sum -Average | ls -l | awk '{s+=$5} END {print s}' |
脚本:变量、条件、循环、函数
| 任务 | CMD(命令提示符) | PowerShell | Bash(Linux/macOS) |
|---|---|---|---|
| 设置变量 # bash:= 两边不能有空格(name = Ada 会运行一个名为 name 的命令)。 | set name=Ada | $name = 'Ada' | name=Ada |
| 在字符串中使用变量 # | echo Hello %name% | "Hello $name" | echo "Hello $name" |
| 算术运算 # CMD 和 bash 只能做整数运算;PowerShell 使用 .NET 数值类型。 | set /a n=5*3 | $n = 5 * 3 | n=$((5 * 3)) |
| 读取用户输入 # | set /p name=Name: | $name = Read-Host 'Name' | read -rp 'Name: ' name |
| 脚本参数 # 在 .bat 文件中,%~1 会去掉两边的引号。param() 块可为 PowerShell 脚本提供命名且带类型的参数。 | %1 %2 … %* | $args[0] or param($Path) | $1 $2 … "$@" |
| 字符串的 if / else # PowerShell 的比较运算符是单词:-eq -ne -gt -lt -like -match。= 和 > 分别是赋值和重定向。 | if "%a%"=="yes" (echo on) else (echo off) | if ($a -eq 'yes') { 'on' } else { 'off' } | if [ "$a" = "yes" ]; then echo on; else echo off; fi |
| 比较数字 # CMD:EQU NEQ LSS LEQ GTR GEQ。 | if %n% GTR 5 echo big | if ($n -gt 5) { 'big' } | if (( n > 5 )); then echo big; fi |
| 判断文件是否存在 # | if exist file.txt echo yes | if (Test-Path file.txt) { 'yes' } | if [ -f file.txt ]; then echo yes; fi |
| 上一个程序的退出码 # 在 PowerShell 中,$? 表示上一条命令的 $true/$false;$LASTEXITCODE 是上一个原生程序的数字退出码。 | echo %ERRORLEVEL% | $LASTEXITCODE | echo $? |
| 仅在成功 / 失败时运行下一条命令 # && 和 || 管道链运算符是 PowerShell 7.0 才加入的;Windows PowerShell 5.1 不接受。 | build && deploy
build || echo failed | build && deploy (PowerShell 7+)
build; if ($?) { deploy } (5.1) | build && deploy
build || echo failed |
| 遍历列表 # | for %i in (a b c) do echo %i | foreach ($x in 'a','b','c') { $x } | for x in a b c; do echo "$x"; done |
| 从 1 循环到 5 # | for /l %i in (1,1,5) do echo %i | foreach ($i in 1..5) { $i } | for i in {1..5}; do echo "$i"; done |
| 逐行遍历文件 # | for /f "usebackq delims=" %l in ("file.txt") do echo %l | foreach ($line in Get-Content file.txt) { $line } | while IFS= read -r line; do echo "$line"; done < file.txt |
| while 循环 # CMD 没有 while;在 .bat 文件中用 goto 加标签实现。 | :loop
set /a i+=1
if %i% lss 5 goto loop | while ($i -lt 5) { $i++ } | while [ "$i" -lt 5 ]; do i=$((i+1)); done |
| 定义并调用函数 # 像调用命令一样调用 PowerShell 函数:Greet Ada,而不是 Greet("Ada")。 | call :greet Ada
goto :eof
:greet
echo Hello %~1
exit /b | function Greet($Name) { "Hello $Name" }
Greet Ada | greet() { echo "Hello $1"; }
greet Ada |
| 将命令输出存入变量 # | for /f "delims=" %i in ('hostname') do set h=%i | $h = hostname | h=$(hostname) |
| 丢弃输出 # | command >nul 2>&1 | command *> $null | command >/dev/null 2>&1 |
| 注释 # | rem comment
:: comment | # comment
<# block #> | # comment |
| 脚本文件及其运行方式 # PowerShell 不会运行当前文件夹中未加 .\ 的脚本,甚至可能完全阻止运行:参见下方的执行策略。 | script.bat | .\script.ps1 | chmod +x script.sh && ./script.sh |
PowerShell 别名陷阱:ls、curl、wget、sc、where
PowerShell 自带一些看起来像 Unix 或 CMD 命令的别名,但实际运行的是参数不同的 cmdlet。具体有哪些别名取决于版本和操作系统。Get-Alias name 可显示某个名称在当前会话中指向什么。
| 你输入 | Windows PowerShell 5.1 | Windows 上的 PowerShell 7 | Linux/macOS 上的 PowerShell 7 |
|---|---|---|---|
curl在 5.1 中输入 curl.exe 才能使用真正的 curl。它的参数(-X、-H、-d)对 Invoke-WebRequest 毫无意义。 | Invoke-WebRequest | 不是别名:运行 curl.exe | 原生 curl |
wget使用 Invoke-WebRequest url -OutFile name,或 curl.exe -LO url。 | Invoke-WebRequest | 不是别名(Windows 默认没有 wget) | 原生 wget(如已安装) |
ls, dirls -la 这类参数在 Windows 上会出错:请用 Get-ChildItem -Force。 | Get-ChildItem | Get-ChildItem | ls = 原生 ls;dir = Get-ChildItem |
cat, type | Get-Content | Get-Content | cat = 原生 cat;type = Get-Content |
cp, mv, rm, rmdirrm -rf 不是合法的 PowerShell 写法:请用 Remove-Item -Recurse -Force。 | Copy-Item, Move-Item, Remove-Item | 相同的 cmdlet | 原生命令 |
ps, kill | Get-Process, Stop-Process | 相同的 cmdlet | 原生命令 |
sort, tee, diff在 Windows 上的 PowerShell 中,diff a b 比较的是对象,而不是两个文件的各行。 | Sort-Object, Tee-Object, Compare-Object | 相同的 cmdlet | 原生命令 |
sc在 5.1 中,sc query 会写入一个名为 query 的文件。请使用 sc.exe。 | Set-Content | 不是别名:运行 sc.exe | 不适用 |
where使用 where.exe 或 Get-Command 查找程序。 | Where-Object | Where-Object | Where-Object |
echoecho -n 不会去掉换行;请用 Write-Host -NoNewline。 | Write-Output | Write-Output | Write-Output |
man | help | help | 原生 man |
引号与转义
大多数“在一个 Shell 里能用、换一个就出错”的问题都出在引号上。每个 Shell 的转义字符都不一样。
| 项目 | CMD | PowerShell | Bash |
|---|---|---|---|
| 字面字符串(不展开变量) | 没有字面引号:即使在 "…" 中 %VAR% 也会展开 | 'Cost: $5' | 'Cost: $5' |
| 含变量的字符串 | "Hello %name%" | "Hello $name, it is $(Get-Date -Format t)" | "Hello $name, it is $(date +%R)" |
| 转义字符 | ^(例如 ^& ^| ^>) | ` 反引号(例如 `n 换行、`t 制表符、`$ 字面 $) | \ 反斜杠 |
| 引号字符串中的引号 | 多数程序在 "…" 中用 "";因程序而异 | 'It''s' 或 "Say `"hi`"" | 'It'\''s' 或 "Say \"hi\"" |
| 续行 | 行尾加 ^ | 行尾加 `(或以 | 结束一行) | 行尾加 \ |
| 脚本中的字面 % 或 $ | .bat 文件中写 %% | 单引号中的 '$' 或 `$ | 单引号中的 '$' 或 \$ |
| 将参数原样传给原生程序 | (不需要) | --% 让 PowerShell 停止解析该行其余部分 | (不需要) |
PowerShell 7.3 改变了向原生程序(curl.exe、git、node)传递引号的方式:带内嵌双引号的参数现在会按原样传递,由 $PSNativeCommandArgumentPassing 控制。在 Windows PowerShell 5.1 中,同样的 JSON 请求体通常需要对内部引号进行两次转义,这也是很多人改用 Invoke-RestMethod 搭配 ConvertTo-Json 的原因。
执行策略:“此系统上禁止运行脚本”
当执行策略为 Restricted 时,PowerShell 会拒绝运行 .ps1 文件;这是 Windows 客户端版本(Windows 10 和 11)上 Windows PowerShell 的实际默认值。Windows Server 默认为 RemoteSigned:本地脚本可以运行,下载的脚本必须签名或解除锁定。在 Linux 和 macOS 上,策略为 Unrestricted,且无法更改。
Get-ExecutionPolicy -List显示各个作用域的策略;定义了策略的最具体作用域生效(组策略优先于所有作用域)。Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser让你自己的脚本无需管理员权限即可运行。Unblock-File .\script.ps1清除你信任的脚本上的“从 Internet 下载”标记。pwsh -ExecutionPolicy Bypass -File script.ps1(5.1 用powershell)只对单个会话应用某个策略。
执行策略是防止误运行脚本的保险,而不是安全边界:任何人都可以把脚本内容粘贴到控制台中运行。
Windows PowerShell 5.1 与 PowerShell 7
- 两个程序:
powershell.exe是 Windows PowerShell 5.1,内置于 Windows,不再增加新功能。pwsh是 PowerShell 7,需单独安装,可跨平台,两者可以并存。 - 7.0 新增的运算符:命令之间的
&&和||、三元运算符$a ? 'yes' : 'no',以及空值合并运算符??/??=。 - 文件编码:5.1 的
>和Out-File写入 UTF-16 LE,Set-Content使用 ANSI 代码页。PowerShell 7 一律写入不带 BOM 的 UTF-8,这正是 Git、Linux 工具和大多数编辑器所期望的。 - 别名:7 在 Windows 上去掉了
curl、wget和sc,在 Linux/macOS 上则把ls、cp、rm、cat、ps等交给原生命令(见上表)。 - 模块差异:
Get-NetIPAddress、Test-NetConnection和Resolve-DnsName等仅限 Windows 的 cmdlet 在 Windows 上的 PowerShell 7 中可用,但在 Linux 或 macOS 上不存在。
在 Windows 上运行 bash:WSL
适用于 Linux 的 Windows 子系统在 Windows 旁运行真正的 Linux 发行版,因此右侧一栏的所有 bash 命令都能照原样运行。在管理员提示符中运行 wsl --install 即可安装,默认发行版为 Ubuntu(Windows 10 版本 2004 及更高版本,以及 Windows 11);wsl -l -v 列出已安装的发行版。
- 从 CMD 或 PowerShell 运行一条 Linux 命令:
wsl ls -la,或跨系统使用管道:dir | wsl grep txt。 - Windows 驱动器在 Linux 中位于
/mnt/c下;在资源管理器中可通过\\wsl.localhost\Ubuntu访问 Linux 文件(旧版本:\\wsl$\Ubuntu)。 - 请把项目放在 Linux 文件系统中(~/),而不是 /mnt/c:跨系统边界访问文件要慢得多。
想深入了解 Linux 这一侧,请参阅Linux 命令速查表。
发现问题,或者觉得哪里可以更好?每条消息我们都会阅读,并尽快修复。
这份 CMD、PowerShell 与 Bash 对照表把同一任务在 Windows 命令提示符、PowerShell 和 bash 中的写法放在同一行:列出和复制文件、在文件中查找文本(PowerShell 中 grep 的对应命令是 Select-String)、环境变量、进程、网络、服务、读写文件内容,以及用变量、条件判断、循环和函数编写脚本。用三种 Shell 中任意一种的命令搜索,就能找到它在另外两种中的对应写法,每条都附有复制按钮。
速查表还涵盖了在几种 Shell 之间切换时常见的问题:看起来像 Unix 命令其实不是的 PowerShell 别名(Windows PowerShell 5.1 中的 curl 和 wget,Windows 上所有版本中的 ls 和 rm)、不同的引号和转义字符、阻止 .ps1 脚本运行的执行策略错误,以及 Windows PowerShell 5.1 与 PowerShell 7 的差异。除非另有说明,PowerShell 命令在两个版本中都适用;没有对应 CMD 命令的地方,表格会如实注明,而不会凭空编造。
使用方法
- 用你熟悉的任意 Shell 命令搜索(例如“grep”“findstr”或“Select-String”),或者按任务搜索(如“结束进程”“环境变量”)。
- 横向阅读该行,找到另外两种 Shell 中的对应命令,点击所需命令旁的“复制”。
- 查看任务名称下方的说明:它会标出版本差异(PowerShell 5.1 与 7)和仅限 Windows 的 cmdlet。
- 如果某条命令的行为与预期不同,请滚动到别名、引号和执行策略部分。
- 使用“打印 / 另存为 PDF”保存一份放在手边;本页在手机上也能使用,每行会变成一张卡片。
常见问题
PowerShell 中 grep 的对应命令是什么?
Select-String。搜索文件用 Select-String -Path app.log -Pattern error,筛选命令输出用 ipconfig | Select-String IPv4。它默认不区分大小写(加 -CaseSensitive 可区分),使用 .NET 正则表达式,-NotMatch 相当于 grep -v。要递归搜索,就把 Get-ChildItem -Recurse -Filter *.log 通过管道传给 Select-String。它的简短别名是 sls。
为什么 curl 在 PowerShell 中表现异常?
在 Windows PowerShell 5.1 中,curl 和 wget 是 Invoke-WebRequest 的别名,所以 -X、-H 和 -d 等 curl 参数会被拒绝或被解释为其他含义。输入 curl.exe 即可运行 Windows 10 1803 及更高版本自带的真正 curl。PowerShell 7 删除了这些别名,所以在那里 curl 运行的就是 curl.exe。在 Linux 和 macOS 上,curl 从来都不是别名。
PowerShell 比 CMD 好吗?
只要不是单纯运行一个程序或一个简短的批处理文件,答案都是肯定的。PowerShell 的管道传递的是结构化对象而不是文本,因此你可以按属性名筛选和排序(Where-Object、Sort-Object),而不必解析列;它还有真正的函数、错误处理、JSON 和 CSV 支持以及远程管理。CMD 依然适合旧的 .bat 文件和一些安装程序,而且所有 CMD 工具(ipconfig、robocopy、netstat)也都能在 PowerShell 中运行。
如何解决“running scripts is disabled on this system”(此系统上禁止运行脚本)?
这是执行策略导致的,Windows 10 和 11 客户端版本默认设为 Restricted。在 PowerShell 中运行 Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser(无需管理员权限)。之后你自己的脚本就能运行,而从互联网下载的脚本必须经过签名,或用 Unblock-File 解除锁定。Get-ExecutionPolicy -List 会显示各作用域的设置;组策略设置会覆盖你自己的任何设置。
可以在 Windows 上运行 bash 命令吗?
可以,借助适用于 Linux 的 Windows 子系统(WSL)。在提升权限的命令行中运行 wsl --install(需要 Windows 10 版本 2004 或更高,或 Windows 11)来安装 Ubuntu,然后从开始菜单打开它,或在 CMD 或 PowerShell 中用 wsl 加命令运行单条命令,例如 wsl grep -rn TODO。Git for Windows 还附带 Git Bash,这是一个更轻量的 bash,包含常用的 Unix 工具。
Windows PowerShell 和 PowerShell 7 有什么区别?
Windows PowerShell 5.1(powershell.exe)内置于 Windows,只接收修复更新。PowerShell 7(pwsh)是当前的跨平台版本,可在 Windows、Linux 和 macOS 上运行,需要单独安装;两者可以同时安装。7 版新增了命令之间的 && 和 ||、三元运算符和 ?? 运算符,默认以 UTF-8 写入文件,并去掉了 curl 和 wget 等容易混淆的别名。
对象与文本:理解 PowerShell 的关键
在 CMD 和 bash 中,管道传递的是文本。要在 bash 中找出占用内存最多的进程,你得用 sort -k 或 awk 从 ps 输出中挑出正确的列,一旦列布局变化,命令就会失效。在 PowerShell 中,管道传递的是带有命名属性的对象,所以同样的任务写作 Get-Process | Sort-Object WS -Descending | Select-Object -First 1。无需任何解析,而且属性名在每台机器上都一样。
实际带来的变化是一种不同的探索方式。在 bash 中,你要读 man 手册来了解输出格式;在 PowerShell 中,把任意命令通过管道传给 Get-Member,就能看到其对象有哪些属性和方法,再用 Where-Object 筛选、用 Select-Object 选取字段。只有当输出到达屏幕或文件时,PowerShell 才会把它转换成文本。
在 PowerShell 中,ipconfig、git 或 curl.exe 等原生程序输出的仍然是文本,所以 Select-String 和 -match 对它们的作用与 grep 相同。它们的退出码保存在 $LASTEXITCODE 中,而不是 $?。
在三种 Shell 之间转换脚本
简单脚本可以逐行转换,但有几处差异几乎人人都会踩坑:
• 比较运算符:CMD 对字符串用 ==,对数字用 EQU、GTR、LSS;PowerShell 用 -eq、-gt、-lt、-like 和 -match(单独的 > 是重定向);bash 在 [ ] 中对字符串用 =,对数字用 -gt 或 (( ))。
• 变量:CMD 中为 %name%(在执行 setlocal EnableDelayedExpansion 后,循环内用 !name!),PowerShell 中为 $name,bash 中为 $name,赋值时 = 两侧不能有空格。
• .bat 文件中的循环要把百分号写两次:在文件中写 for %%f in (*.txt),在命令行中写 for %f。
• 路径:在 Windows 上,PowerShell 同时接受 / 和 \;Linux 上的 bash 需要用 /。环境变量在 Windows 上不区分大小写,在 Linux 上区分大小写。
• 错误:CMD 在失败后会继续执行,除非你检查 %ERRORLEVEL%;bash 会继续执行,除非设置了 set -e;PowerShell 在遇到非终止错误后会继续执行,除非设置 $ErrorActionPreference = 'Stop'。
如果脚本需要同时在 Windows 和 Linux 上运行,使用 PowerShell 7 或 WSL 下的 bash 可以避免维护两份副本。
相关免费工具
- Linux 命令速查表 — 按任务分类的 Linux 命令,从文件和权限到网络、systemd 和文本处理。每条都附常用参数、可复制的示例和 macOS 差异说明。
- Windows 快捷键 — 可搜索、可打印的 Windows 11 全部快捷键:Win 键、窗口贴靠、虚拟桌面、截图、文件资源管理器。
- Mac 键盘快捷键 — 全部 macOS 快捷键,附 ⌘ ⌥ ⌃ ⇧ 符号说明:截图、窗口平铺、访达、Safari 和特殊字符。
- curl 转代码 — 粘贴 curl 命令(包括 Chrome 的“Copy as cURL”),即可得到 Python、JavaScript、Node、Go、PHP、Ruby、Java、C#、wget 或 HTTPie 版本的相同请求。
- Git 速查表 — 按你想做的事整理 Git 命令:撤销上一次提交、重命名分支、删除远程分支。优先给出新式 switch/restore 命令并附经典写法,危险操作有醒目标记。