跳转到内容

第 4 章 · 终端与 Shell

一句话:终端是敲命令的窗口,Shell 是解释命令的程序;本书所有命令都在这一对组合里运行。 用它还是用别的:Windows 上用 Windows Terminal 加 PowerShell 7;教程只给 Linux 命令、或项目要在 Linux 服务器上跑时,用 WSL 里的 bash;macOS 用自带终端和 zsh。 核对版本:PowerShell 7.6、Windows Terminal 1.24、bash 5.2,2026-10

Windows:

终端窗口
winget install Microsoft.WindowsTerminal
winget install Microsoft.PowerShell

Windows 11 已自带 Windows Terminal,可以跳过第一条。PowerShell 7 装好后,Windows Terminal 的下拉菜单里多出一个名为“PowerShell”的配置文件;名为“Windows PowerShell”的那个是系统自带的 5.1。

要在 Windows 里用 Linux,以管理员身份打开 PowerShell 运行下面这条,默认装 Ubuntu,装完要重启,完整步骤见 4.4:

终端窗口
wsl --install

macOS 自带“终端”应用,默认 Shell 是 zsh,不用装。想要分屏、搜索更顺手的终端,可以装 iTerm2:

终端窗口
brew install --cask iterm2

Linux 桌面版自带终端,默认 Shell 是 bash,不用装。

查版本。PowerShell 看 Major 一列,7 才是 PowerShell 7;wsl --version 第一行是 WSL 版本:

终端窗口
$PSVersionTable.PSVersion
wsl --version
终端窗口
bash --version
  • 终端(Terminal):显示文字、接收键盘输入的窗口程序,比如 Windows Terminal、macOS 的终端、VS Code 底部的集成终端(第 1 章)。它管字体、配色、标签页和分屏,自己不认识任何命令。
  • Shell:在终端里运行、真正解释你敲的命令的程序,比如 PowerShell、bash、zsh。同一个终端里可以开不同的 Shell,命令写法跟着 Shell 走,跟终端无关。
  • PowerShell 7 与 Windows PowerShell 5.1:两个独立的程序,可以同时装在一台机器上。7 的程序名是 pwsh,5.1 是 powershell;配置文件、已装的模块各存一份。本书的 PowerShell 命令都按 7 写,在 5.1 里个别命令会不一样,比如 curl,见 4.6。
  • WSL(Windows Subsystem for Linux):在 Windows 里运行一个真正的 Linux 发行版,里面是原版的 bash、apt 和 Linux 命令。Docker Desktop 在 Windows 上也靠它运行(第 12 章)。
  • 环境变量与 PATH:环境变量是 Shell 传给它启动的每个程序的一组“名字=值”。其中 PATH 是一串目录,你敲 git 时,Shell 按顺序在这些目录里找 git 程序,找不到就报“找不到命令”。
  • 管道(Pipeline):用 | 把前一条命令的输出交给后一条。bash 里传的是一行行文本,要靠 grep、cut 按列切;PowerShell 里传的是对象,可以直接按属性筛选排序,比如 Get-Process | Sort-Object CPU -Descending | Select-Object -First 5 列出最占 CPU 的五个进程。

三层的关系如下:终端只是外壳,换终端不换 Shell,命令写法不变;换了 Shell,同一件事的写法就变了,这正是 4.3 那张对照表要解决的事。

终端、Shell、操作系统三层:终端里运行 Shell,Shell 让操作系统执行命令;命令写法由中间的 Shell 决定

PowerShell 7 给 ls、cat、cd、pwd、cp、mv、rm 都设了别名,不带参数时和 bash 一样用;一旦带上 -la、-rf 这种 bash 写法的参数就会报错,要换成右列的写法。bash 一列在 Linux、WSL 和 macOS 的 zsh 里都能用。Ctrl+R、Ctrl+L 在 macOS 上也是按 Ctrl,不是 Cmd。

任务 bash PowerShell
文件与目录
看当前目录 pwd pwd
列出文件,含隐藏文件 ls -la Get-ChildItem -Force
进入目录;回到上一个目录 cd <目录>;cd - cd <目录>;cd -
建多级目录 mkdir -p a/b/c mkdir a/b/c
建空文件 touch a.txt New-Item a.txt
复制目录 cp -r <源> <目标> Copy-Item -Recurse <源> <目标>
移动或改名 mv a.txt b.txt Move-Item a.txt b.txt
删除目录及里面所有内容 rm -rf <目录> Remove-Item -Recurse -Force <目录>
看文件内容 cat <文件> Get-Content <文件>
看前 20 行 head -n 20 <文件> Get-Content <文件> -TotalCount 20
看后 20 行 tail -n 20 <文件> Get-Content <文件> -Tail 20
实时跟踪日志,Ctrl+C 停止 tail -f app.log Get-Content app.log -Wait -Tail 20
打包成 tar.gz tar -czf a.tgz <目录> tar -czf a.tgz <目录>
解开 tar.gz tar -xzf a.tgz tar -xzf a.tgz
查找
按文件名找 find . -name "*.log" Get-ChildItem -Recurse -Filter *.log
在所有文件里找文字 grep -rn "TODO" . Get-ChildItem -Recurse -File | Select-String "TODO"
在指定文件里找文字 grep -n "TODO" *.py Select-String -Path *.py -Pattern "TODO"
环境
看全部环境变量 env Get-ChildItem Env:
看一个变量 echo $NODE_ENV $env:NODE_ENV
设变量,只在当前终端有效 export NODE_ENV=production $env:NODE_ENV = "production"
看 PATH,一行一个目录 echo $PATH | tr ':' '\n' $env:PATH -split ';'
命令在哪个位置 which git Get-Command git
看命令帮助 man ls Get-Help Get-ChildItem
进程与网络
看进程 ps aux | grep node Get-Process node
按 PID 结束进程 kill <PID> Stop-Process -Id <PID>
按名字结束进程 pkill node Stop-Process -Name node
谁占用了 3000 端口 lsof -i :3000 Get-NetTCPConnection -LocalPort 3000 -State Listen
发 HTTP 请求 curl -I https://example.com curl.exe -I https://example.com
调 JSON 接口(PowerShell 直接得到对象) curl -s <url> Invoke-RestMethod <url>
历史与效率
搜索历史命令 Ctrl+R 后输入几个字 Ctrl+R 后输入几个字
重新执行上一条命令 !! r
清屏 clear 或 Ctrl+L cls 或 Ctrl+L
设命令别名 alias ll='ls -la' Set-Alias ll Get-ChildItem
重定向
输出写进文件,覆盖原内容 <命令> > out.txt <命令> > out.txt
追加到文件末尾 <命令> >> out.txt <命令> >> out.txt
丢弃输出 <命令> > /dev/null <命令> > $null
输出和错误写进同一个文件 <命令> > all.txt 2>&1 <命令> > all.txt 2>&1
只把错误写进文件 <命令> 2> err.txt <命令> 2> err.txt

几点补充:

  • lsof 没装时,Linux 上用 ss -ltnp,最后一列是占用端口的进程。PowerShell 的结果里 OwningProcess 一列是 PID,接着用 Get-Process -Id <PID> 看它是谁。
  • 进程与网络这几行的 bash 写法要在 WSL 或 Linux 里用;Git Bash 的 ps、kill 只看得到 Git Bash 自己启动的进程。
  • PowerShell 7 里 curl 就是真正的 curl 程序;在 5.1 里它是另一条命令的别名,所以表里一律写 curl.exe,两个版本都对。
  • PowerShell 的别名只能换个名字,不能带参数;ll 想带参数,要写成函数,见 4.5。
  • 在大项目里找文字,rg 比 grep 和 Select-String 快得多,两边写法相同,见第 5 章。登录远程服务器用 ssh,见第 6 章。

Windows Terminal 只有 Windows 版,下面的快捷键表只适用于 Windows;macOS 终端和 iTerm2 的分屏、标签页快捷键在它们各自的菜单里能看到。

操作 快捷键 说明
新标签页 Ctrl+Shift+T 用默认配置文件,改默认见 4.4
选一个配置文件开新标签页 Ctrl+Shift+Space 弹出下拉菜单,PowerShell、Ubuntu 等都在里面
向右拆分窗格 Alt+Shift++ 新窗格和当前窗格用同一个配置文件
向下拆分窗格 Alt+Shift+- 一边跑服务、一边看日志时用
在窗格之间切换 Alt+方向键 当前窗格有彩色边框
关闭当前窗格 Ctrl+Shift+W 只剩一个窗格时关掉整个标签页
设置 Ctrl+, 图形界面;Ctrl+Shift+, 直接打开 settings.json
命令面板 Ctrl+Shift+P 记不住快捷键时搜操作名

把 Windows Terminal 的默认 Shell 改成 PowerShell 7

Section titled “把 Windows Terminal 的默认 Shell 改成 PowerShell 7”

打开 Windows Terminal 默认进的往往是 5.1,本书的命令按 7 写:

  1. 装 PowerShell 7:winget install Microsoft.PowerShell。
  2. 关掉所有 Windows Terminal 窗口再打开,按 Ctrl+Shift+Space,确认下拉菜单里有“PowerShell”。
  3. 按 Ctrl+, 打开设置。
  4. 左侧选“启动”,“默认配置文件”选“PowerShell”,不是“Windows PowerShell”。
  5. 点右下角“保存”。
  6. 按 Ctrl+Shift+T 开新标签页,运行 $PSVersionTable.PSVersion,Major 是 7 就成功了。

VS Code 集成终端用哪个 Shell 另外设置,见第 1 章的 terminal.integrated.defaultProfile.windows。

装 WSL,在 VS Code 里打开 WSL 里的项目

Section titled “装 WSL,在 VS Code 里打开 WSL 里的项目”

教程只给 Linux 命令,或项目依赖 Linux 才有的工具时,在 WSL 里开发:

  1. 以管理员身份打开 PowerShell,运行 wsl --install。
  2. 装完重启电脑。
  3. 重启后从开始菜单打开 Ubuntu,按提示设 Linux 用户名和密码,以后 sudo 要输这个密码。
  4. 更新软件包:sudo apt update && sudo apt upgrade。
  5. 在 Linux 家目录下建项目目录:mkdir -p ~/projects && cd ~/projects,不要放在 /mnt/c 下,原因见 4.6。
  6. 下载项目:git clone <url>,然后 cd 进项目目录。
  7. 在 Windows 这边给 VS Code 装 WSL 扩展(第 2 章):code --install-extension ms-vscode-remote.remote-wsl。
  8. 回到 WSL 的项目目录,用 VS Code 打开:code .。第一次会先在 WSL 里装好 VS Code 的服务端,左下角显示“WSL: Ubuntu”就对了。
  9. 要在 Windows 资源管理器里看这些文件:explorer.exe .。

以后在 Windows Terminal 里按 Ctrl+Shift+Space 选“Ubuntu”,就直接进 WSL。

$env:PATH 和 export PATH 只在当前终端有效,关掉就没了。要每次打开都有,写进 Shell 的配置文件。PowerShell:

  1. 看配置文件在哪:$PROFILE。
  2. 文件还不存在就新建:if (!(Test-Path $PROFILE)) { New-Item -Path $PROFILE -ItemType File -Force }。
  3. 用 VS Code 打开:code $PROFILE。
  4. 加一行并保存:$env:PATH += ";$HOME\tools"。
  5. 让当前终端立即生效:. $PROFILE。
  6. 检查最后一个目录是不是它:$env:PATH -split ';' | Select-Object -Last 1。

bash(Linux、WSL、Git Bash);macOS 的 zsh 把 ~/.bashrc 换成 ~/.zshrc:

  1. 追加一行到配置文件:echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc。
  2. 让当前终端立即生效:source ~/.bashrc。
  3. 检查第一个目录是不是它:echo $PATH | tr ':' '\n' | head -3。

$PROFILE 只对 PowerShell 生效。要让 Windows 上所有程序都看到这个目录,在开始菜单搜“环境变量”,打开“编辑账户的环境变量”,在用户变量 Path 里新建一行,然后重开终端。

配置文件的位置:

范围 路径
PowerShell 7 $HOME\Documents\PowerShell\Microsoft.PowerShell_profile.ps1,以 $PROFILE 的输出为准
Windows PowerShell 5.1 $HOME\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
bash(Linux、WSL、Git Bash) ~/.bashrc
zsh(macOS) ~/.zshrc
Windows Terminal %LOCALAPPDATA%\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json
PowerShell 的历史记录 %APPDATA%\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt

“文档”文件夹被 OneDrive 或其他盘接管时,PowerShell 配置文件的实际位置会变,所以永远以 $PROFILE 的输出为准。Windows Terminal 的配置不用记路径,按 Ctrl+Shift+, 直接打开。

值得改的项:

配置项 建议值 效果
Windows Terminal 默认配置文件(defaultProfile) PowerShell 新标签页直接进 PowerShell 7,步骤见 4.4
Windows Terminal 字体(font.face) 等宽且带中文的字体,如更纱黑体 Sarasa Mono SC 中英文对齐,表格类输出不错位;默认是 Cascadia Mono
Windows Terminal 回滚行数(historySize) 50000 默认 9001 行,长日志能往上翻得更远
PowerShell 历史条数(Set-PSReadLineOption -MaximumHistoryCount) 10000 Ctrl+R 能搜到更早的命令
bash 历史条数(HISTSIZE、HISTFILESIZE) 10000、20000 同上
PowerShell 输出编码([Console]::OutputEncoding) UTF-8 外部程序输出的中文不乱码
提示符 Oh My Posh 或 Starship 提示符里显示当前 Git 分支、Python 虚拟环境;两者都支持 PowerShell、bash 和 zsh

Windows Terminal 的字体和回滚行数写在 settings.json 的 profiles → defaults 里,对所有配置文件生效,设置界面里是“配置文件”→“默认值”;defaultProfile 在 settings.json 的最外层,界面里在“启动”下改,见 4.4。

PowerShell 最小配置,写进 $PROFILE:

终端窗口
[Console]::OutputEncoding = [Text.Encoding]::UTF8 # 外部程序输出的中文按 UTF-8 显示
$env:PATH += ";$HOME\tools" # 把自己的工具目录加到 PATH 末尾
Set-Alias -Name g -Value git # 简单别名:只换名字,不能带参数
function gs { git status -s @args } # 带参数的"别名"写成函数
Set-PSReadLineOption -MaximumHistoryCount 10000 # 多存一些历史命令

bash 最小配置,写进 ~/.bashrc(macOS 的 zsh 写进 ~/.zshrc,LANG 那行改成 export LANG=en_US.UTF-8,最后三行改成 HISTSIZE=10000 和 SAVEHIST=20000):

终端窗口
export PATH="$HOME/.local/bin:$PATH" # 把自己的工具目录加到 PATH 最前面
export LANG=C.UTF-8 # 终端和命令输出用 UTF-8
alias ll='ls -la' # 列出全部文件
alias gs='git status -s' # 简短的 Git 状态
HISTSIZE=10000 # 当前会话记住的历史条数
HISTFILESIZE=20000 # 历史文件里保存的条数
HISTCONTROL=ignoredups # 连续重复的命令只记一次
  • 运行脚本报“无法加载文件 …,因为在此系统上禁止运行脚本”。 原因:执行策略不允许运行脚本;PowerShell 7 的原文是“因为此系统上已禁用脚本运行”。处理:Set-ExecutionPolicy RemoteSigned -Scope CurrentUser,详见第 1 章。
  • PowerShell 里程序输出的中文变成“涓枃杈撳嚭”这样的乱码。 原因:控制台按 GBK 解码,程序输出的是 UTF-8。处理:运行 [Console]::OutputEncoding = [Text.Encoding]::UTF8,写进 $PROFILE 长期生效,见 4.5。
  • 照教程运行 curl -I <url>,报“无法处理命令,因为一个或多个强制参数丢失: Uri。“或停下来让你输入 Uri。 原因:Windows PowerShell 5.1 里 curl 是 Invoke-WebRequest 的别名。处理:写成 curl.exe,或改用 PowerShell 7。
  • rm -rf <目录> 报“找不到与参数名称 ‘rf’ 匹配的参数。” 原因:PowerShell 的 rm 是 Remove-Item 的别名,参数不能合写。处理:Remove-Item -Recurse -Force <目录>;ls -la 同理改成 Get-ChildItem -Force。
  • 刚装的工具报“术语 ‘…’ 不会被识别为 cmdlet、函数、脚本文件或可执行程序的名称”或 command not found。 原因:终端只在启动时读一次 PATH。处理:关掉终端重开,VS Code 要整个窗口重开。
  • WSL 里 npm install、git status 慢得离谱。 原因:项目在 /mnt/c/... 下,Linux 跨系统读 Windows 的文件很慢。处理:把项目移到 Linux 家目录,如 ~/projects,再用 code . 打开。
  • 脚本在 Linux 上报 $'\r': command not found 或 cannot execute: required file not found。 原因:脚本是 CRLF 换行。处理:sed -i 's/\r$//' <脚本>;根治见第 7 章 .gitattributes。
  • 路径带空格时,cd my dir 报“找不到接受自变量 ‘dir’ 的位置参数。“或 cd: too many arguments。 原因:Shell 按空格把路径拆成了两个参数。处理:整个路径加引号,如 cd "my dir";用 Tab 补全路径时,Shell 会自动处理空格。
  • Windows Terminal 文档:安装、设置界面、配置文件、窗格和快捷键的官方说明。
  • PowerShell 文档:PowerShell 7 的安装、配置文件、执行策略和全部 cmdlet 参考。
  • WSL 文档:安装 WSL、设置 Linux 用户、跨文件系统工作和 VS Code 配合。
  • Bash 参考手册:GNU 官方手册,重定向、变量、启动文件的准确规则都在这里。
  • ExplainShell:粘贴一条 bash 命令,逐段解释每个部分和参数的含义。