上一章你只是「会用」终端;这一节要把这台机器拆开看——你敲的每一个字,到底被谁接走、被谁读懂、又由谁去执行;命令是从哪儿找出来的(PATH);前台与后台是怎么回事。搞清楚这一层,后面三节(常用指令、权限、目录结构)才不会变成死记硬背。
3-1 讲了「终端机是什么」、3-5 讲了「有哪些命令」——本节讲的是它们中间那一层:命令行是怎么运作的。 换句话说:3-5 是「给你一本词典」,本节是「告诉你这门语言的语法」。 读完本节再看 4-2 的常用指令表,你会发现那些命令不是一盘散沙,而是同一个套路的不同零件。
一、先把三个角色摆清楚:终端机、Shell、内核
你在屏幕上敲命令时,其实是三个角色在接力:
| 角色 | 大白话 | 具体是什么 |
|---|---|---|
| 终端机(terminal) | 一张「纸」——负责显示和接收你敲的字 | 窗口程序(如 lxterminal),或你 SSH 连过来的那条通道 |
| Shell(壳) | 一个「翻译官」——读你的字,理解意思,转给系统 | 最常见的是 bash,也可能是 zsh |
| 内核(kernel) | 干活的人——真正管 CPU、内存、磁盘、网卡 | Linux 内核本体 |
终端机是「脸」,Shell 是「嘴」,内核是「手」。
你对着脸说话(打字),嘴把话解释成命令,手去执行。
换终端机不影响命令——同一个命令,在桌面窗口里、在 SSH 里、在图形界面按 F4 弹出的窗口里,结果完全一样(这也是 3-2 那句「图形和命令行是同一个世界」的由来)。
那到底「命令行(command line)」指的是什么? 它指的是用文字下命令这种工作方式,跟「图形界面(点图标)」相对。终端机是干这件事的窗口,Shell 是干这件事的程序。
二、敲下一条命令,机器走了四步
这是本节最值钱的一段。以你敲 ls -l /home 为例:
| 步骤 | 谁在做 | 做了什么 |
|---|---|---|
| ① 接收 | 终端机 | 把这一行字交给 Shell |
| ② 拆词 | Shell | 按空格切成三块:ls(命令)、-l(选项)、/home(参数) |
| ③ 找命令 | Shell | 去 PATH 列出的几个目录里挨个翻,看哪个目录里有叫 ls 的可执行文件 |
| ④ 执行 | 内核 | 把找到的程序加载起来跑,结果送回终端机显示 |
第 ③ 步是新手最常撞墙的地方,后面第五节单独讲。
还有一件常被忽略的事:Shell 在执行前,还会自己动手做几件「预处理」,比如:
- 把通配符摊开:你写
ls *.txt,是 Shell 先把*.txt换成一串真实文件名,再把结果交给ls。命令本身并不知道*是什么。 - 处理重定向和管道:
>、>>、|也是 Shell 先接手的(3-5 讲过这三个,本节第六节再补上「为什么不只两个流」)。 - 把变量换成值:
echo $HOME里的$HOME是 Shell 换掉的。
所以有一句行家话:「你面对的不是命令,是 Shell。」 出错时先分清是 Shell 没理解你的意思(语法错),还是命令本身报的错(执行错)——这两类错的修法完全不同。
三、打开终端机的六种方式(比 3-5 多三种)
3-5 给过三种,这里补全,并告诉你各自什么时候用:
| # | 方式 | 怎么用 | 特点 / 什么时候用 |
|---|---|---|---|
| 1 | 桌面快捷键 | Ctrl + Alt + T |
最快,桌面在手边时首选 |
| 2 | 菜单 | 主菜单搜 terminal |
快捷键失效时的退路 |
| 3 | 文件管理器里按 F4 |
在某个目录里就地开终端 | 路径自动落在该目录,最省事(3-2 讲的) |
| 4 | SSH 远程 | 从 Windows 用 ssh 用户名@主机 |
无头模式唯一的路(2-5 讲的) |
| 5 | 虚拟控制台 | 按 Ctrl + Alt + F1~F6 |
图形界面卡死时的救命通道;Ctrl + Alt + F7(或 F1)切回桌面 |
| 6 | 开机自动进命令行 | sudo raspi-config 里设开机方式 |
服务器用法,2-4 提过 |
图形界面点不动了、窗口全卡住,别急着拔电——按 Ctrl + Alt + F2(或 F1~F6 任一),你会看到一个纯黑底白字的登录提示,这是同一个系统的另一个「入口」,tty 虚拟控制台。
在这里登录后 sudo reboot 就能救回来。这是 3-2 那条「拔电永远是最后一步」的底气所在。
四、一条命令的三个部件(复习 + 升级)
| 部件 | 位置 | 例子里是 | 说明 |
|---|---|---|---|
| 命令 | 第一个词 | ls |
程序名 |
| 选项(option) | 一般以 - 开头 |
-l |
调行为;-l 短选项,--long 长选项,多数命令两者等价 |
| 参数(argument) | 命令作用的对象 | /home |
路径、文件名、字符串 |
三条实用规则(3-5 提过,这里给出原因):
- 短选项能合并:
ls -l -a=ls -la(Shell 不管,是ls自己认的规矩)。 - 选项和参数的顺序,只有命令自己在意:一般要先写选项,但很多命令也接受
ls /home -l(不推荐)。 --是分界线:如果文件名本身以-开头(比如-weird.txt),写rm -- -weird.txt告诉命令「后面这个是文件名,不是选项」。
不记得某命令怎么用? 分别试这三招(从轻到重):
ls --help # 短说明,最快
man ls # 完整说明书,按 q 退出
man -k 关键词 # 按关键词找命令,例:man -k password
man ls 里按 / 可以搜关键词,按 n 跳到下一个匹配。
五、命令到底住在哪里:PATH 与「命令的三种出身」
PATH 是一串目录清单,Shell 找命令时按这个清单从左到右挨个翻。
echo $PATH
# 典型输出(用冒号分隔):
# /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games
看这个输出要读出三件事:
- 清单里的目录顺序就是优先级——两个目录都有同名命令时,左边的赢。
/usr/bin和/bin都在里面,但现在的系统里它俩其实是同一个地方(/bin是指向/usr/bin的快捷方式)——这就是 4-4 要讲的「/usr合并」,老资料把它们当两个目录讲,容易看得糊涂。- 如果某个命令不在这串目录里,你就得写全路径(如
./myscript.sh)或者把它所在的目录加进PATH。
查一个命令的底细,用这四个:
| 命令 | 干什么 | 例子 |
|---|---|---|
which 命令 |
找出它在哪个目录(最常用) | which python3 |
type 命令 |
看出它属于哪一类(下面那张表) | type cd |
command -v 命令 |
同上,但更适合写脚本(结果最标准) | command -v git |
whereis 命令 |
连程序、源码、手册一起找 | whereis bash |
用 type 能看出命令的三种出身——这是本节最容易被跳过、又最有用的一点:
| 出身 | type 的输出 |
例子 | 说明 |
|---|---|---|---|
| 内建(builtin) | cd is a shell builtin |
cd、echo、pwd |
Shell 自己实现的,磁盘上没有这个可执行文件!所以 which cd 查不到是正常的 |
| 外部程序 | ls is /usr/bin/ls |
ls、apt、python3 |
磁盘上一个真实文件,靠 PATH 找到 |
| 别名(alias) | ll is aliased to 'ls -l' |
常有人把 ll 设成 ls -l |
你或系统起的昵称,只是替换文字 |
有人照着教程敲 which cd,返回空,就以为「系统坏了」——没坏,cd 是内建命令,本来就不在磁盘上。同理,看到别人的 type ll 有输出、自己全无,那只是因为对方设了别名。先分清出身,再谈「命令找不到」。
顺手认一下别名的两个动作(可选,知道有这回事就行):
alias # 列出当前所有别名
alias ll='ls -l' # 临时加一个(关掉这个终端就没了)
六、命令的输出不只有一路:三个「流」
3-5 讲了 > 和 >>,这里补上它们的完整版图。
Unix 给每个命令配了三个标准通道:
| 编号 | 名字 | 装什么 | 重定向写法 |
|---|---|---|---|
| 0 | 标准输入 stdin | 命令要读的输入 | < |
| 1 | 标准输出 stdout | 命令正常的结果 | > 或 >> |
| 2 | 标准错误 stderr | 命令报错的信息 | 2> |
这就解释了一件新手常困惑的事:为什么 ls 不存在的文件 > out.txt,屏幕上照样跳出错误提示、而 out.txt 里是空的?
因为报错走的是第 2 路(stderr),而 > 只搬第 1 路(stdout)。 两条路各走各的。
把两路都收进同一个文件:
| 写法 | 含义 | 备注 |
|---|---|---|
命令 > all.txt 2>&1 |
正常输出和报错都进 all.txt |
传统写法,最好认 |
命令 &> all.txt |
同上 | bash 简写,更短 |
命令 > /dev/null 2>&1 |
全都扔掉(静默) | 写脚本时常用来「假装没这回事」 |
命令 2> err.txt |
只把报错收进文件 | 排查问题时特别有用 |
它是系统的「黑洞文件」——写进去的东西直接消失,永远读不回来。想「不看到输出但保留命令效果」(比如定时任务里不想被刷屏),就把它扔进这里。
七、前台、后台与作业控制(3-5 完全没讲的一层)
前台=命令占用着你的终端,你得等它跑完才能敲下一条。 后台=命令在背后跑,你立刻能把终端拿回来。
| 动作 | 键 / 命令 | 说明 |
|---|---|---|
| 打断当前命令 | Ctrl + C |
最常用的「救命键」——命令卡住了、跑太久、刷屏了,按它 |
| 暂停并退回提示符 | Ctrl + Z |
与 Ctrl + C 不同:它是挂起,没杀死 |
| 让命令在后台跑 | 命令末尾加 & |
如 python3 long_task.py & |
| 看后台有哪些作业 | jobs |
给每个作业一个编号 [1]、[2] |
| 把作业拉回前台 | fg(或 fg %1) |
回去继续看着它 |
| 让挂起的作业在后台继续 | bg |
配合 Ctrl + Z 用 |
再区分一个极易混淆的概念:
- 作业(job):Shell 管的,专指「这个终端里启动的程序」,重启终端就没了。
- 服务/进程(process):系统管的一直在跑的程序(如 SSH 服务),用
ps、top、systemctl看——这属于 4-2 的内容。
用 & 放在后台的程序,多数会跟着终端一起结束(因为它是这个 Shell 的孩子)。
想让它真正「断线也活着」,要用 nohup 命令 & 或 setsid,或者干脆做成 systemd 服务。
别指望 & 能保命——这是很多教程一带而过、新手却踩得最疼的一点。
八、命令「成功还是失败」:退出码 $?
每个命令跑完,都会留下一个数字表示结果:
| 数值 | 含义 |
|---|---|
| 0 | 成功 |
| 非 0(1~255) | 失败,具体数字由程序自己定义 |
ls /home
echo $? # 输出 0 —— 上一条命令成功了
ls /不存在的目录
echo $? # 输出 2 —— 上一条命令失败了
这在写脚本时是核心:if、&&、|| 全靠它判断。你现在只需要记住一件事:
&&=前面成功才继续(前面失败就停),||=前面失败才执行后面。 例:sudo apt update && sudo apt upgrade——更新索引成功,才去升级,这是最常用的组合(4-5 会反复用到)。
九、动手 Demo:让机器把你的「出身」讲一遍
在树莓派上(桌面终端或 SSH 里都行)依次跑这七步:
# 1. 你现在是谁、在哪个 Shell 里
whoami
echo $SHELL
# 2. 看命令是从哪些目录找出来的
echo $PATH
# 3. 三种出身各验一个
type cd
type ls
alias ll 2>/dev/null || echo "(没有 ll 这个别名,正常)"
# 4. 同一条命令,分别用「外部程序」和「内建」两种身份看
command -v echo
type echo
# 5. 看退出码:先成功,再失败
ls /home
echo $?
ls /this_does_not_exist
echo $?
# 6. 两条流分开收
ls /home /this_does_not_exist > out.txt 2> err.txt
echo "--- out.txt ---"; cat out.txt
echo "--- err.txt ---"; cat err.txt
# 7. 收尾:命令卡住时怎么脱身(先跑一个长命令,再按 Ctrl + C)
sleep 100
看到什么算成功:
| 步骤 | 预期看到 |
|---|---|
| 1 | 你的用户名;/bin/bash(或 /usr/bin/bash——它俩是同一个文件,4-4 会解释) |
| 3 | 第一行含 shell builtin;第二行含 /usr/bin/ls;第三行要么列出一个别名,要么打印「(没有…正常)」 |
| 4 | command -v echo 很有可能有输出,但 type echo 说它是 builtin——因为在多数系统里 Shell 内建的同名命令会优先 |
| 5 | 第一次 0;第二次非 0(常见是 2) |
| 6 | out.txt 里是 /home 下的内容;err.txt 里是那句报错——两条流真的分开了 |
| 7 | 屏幕停住不动,按 Ctrl + C 立刻回到提示符 |
做完之后检查一下(两条流那个实验留下的文件):
ls -l out.txt err.txt
rm out.txt err.txt
「读结果」提示:第 6 步是本节的核心验收——它把「报错不算输出」这件事从说法变成了你看得见的事实。第 7 步是保命技能:以后任何命令刷屏不止、卡着不动,第一反应就是
Ctrl+C。
十、30 秒实验
验证「Shell 先摊开通配符」这句话。
- 建三个文件:
mkdir -p ~/wildcard_test && cd ~/wildcard_test && touch a.txt b.txt c.log
- 用
echo看通配符被换成了什么(echo只是把收到的词原样打印):
echo *.txt
echo *
- 清理:
cd ~ && rm -r ~/wildcard_test
你会看到:echo *.txt 打印 a.txt b.txt;echo * 打印三个文件。echo 根本不知道有通配符这回事——是 Shell 在把 *.txt 交给它之前就已经换好了。
这 30 秒你收获的是:以后写 rm *.log 这种命令时,你会知道真正决定删哪些文件的是 Shell,所以「先 echo 看一眼再 rm」这个保命习惯(3-5 提过)是有原理支撑的,不是迷信。
十一、常见误区
- 「终端机就是命令行」:不是一回事。终端机是那个窗口,命令行是用文字下命令这种方式,Shell 是中间那个翻译程序。三者各有分工(见第一节)。
- 「
cd查不到路径,说明系统有问题」:cd是 Shell 内建命令,磁盘上本来就没有这个文件。用type看,别用which判断。 - 「
>能把所有输出都存下来」:只存正常输出。命令的报错走 stderr,要写> all.txt 2>&1或&> all.txt(第六节)。 - 「命令后面加
&就是常驻后台了」:关掉终端它多半会一起死。真要长期运行,用nohup、setsid或做成 systemd 服务(第七节)。 - 「命令卡住了只能关窗口或拔电」:先按
Ctrl+C。它是专门用来打断当前命令的;Ctrl+Z是挂起(不是杀死),fg/bg管它。 - 「命令报错时,看屏幕上那段字就够了」:那只是 stderr;退出码
$?才是程序给出的正式结论——脚本里判成败靠的是它,不是肉眼。 - 「通配符是命令的功能」:是 Shell 先展开的。这就是为什么「把
rm *.log先换成echo *.log看一眼」能救命。
自测三问
1. 终端机、Shell、内核各干什么?一句话说清。(**终端机是脸——收字显示;Shell 是嘴——解释你的意思;内核是手——真正干活**) 2. 敲一条命令时,Shell 会自己先做哪三件「预处理」?(**摊开通配符;处理重定向与管道;把 `$变量` 换成值**) 3. 为什么 `ls 不存在的文件 > out.txt` 里,报错仍然显示在屏幕上?(**报错走 stderr(第 2 路),而 `>` 只搬 stdout(第 1 路);要连报错一起收得写 `> out.txt 2>&1`**)- ☐ 下一节(4-2 Linux 的常用指令)
相关笔记
- 在 Raspberry Pi OS 执行命令 —— 上一章:命令本身怎么敲(本节讲它背后的机制)
- 认识 Linux、终端机和桌面环境 —— 终端机与 Shell 是什么
- 使用 Raspberry Pi OS 桌面环境 ——
F4就地开终端、图形卡住时的出口 - 网络连接与蓝牙装置 —— SSH 这条「命令行入口」
- 🍓 树莓派 · 索引 —— 全课路线图