无交互CLI——用户流程的最简形态

从最简单的程序开始。用户输入一行命令,程序运行,输出结果,结束。用户流程在这里是一条直线——没有状态,没有回退,没有选择。但正是这条直线,定义了所有后续交互形态的起点。


一、一条直线

1
2
3
$ grep "hello" file.txt
hello world
$

用户做了三件事:

1
2
3
1. 输入命令
2. 等待
3. 看到输出

程序做了三件事:

1
2
3
1. 接收参数
2. 执行
3. 输出结果

两者之间的关系:

1
用户输入  →  程序执行  →  用户看到结果

没有中间状态。 程序运行期间用户不能干预,用户输入之后程序不能追问。整个交互过程就是一条直线。


二、直线的结构

1
2
3
4
5
6
7
8
9
10
11
12
sequenceDiagram
participant U as 用户
participant T as 终端
participant P as 程序

U->>T: 输入命令行
T->>P: argc, argv
Note over P: 执行中...<br/>用户无法干预
P->>T: stdout 输出
T->>U: 看到结果
Note over P: 程序退出
Note over U: 用户重新获得控制权

把这条直线拆开:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
用户                          程序
│ │
├─ 输入: grep "hello" file.txt
│ │
│ ┌──────┴──────┐
│ │ main() │
│ │ parse_args() │
│ │ search() │
│ │ output() │
│ └──────┬──────┘
│ │
│ 输出: hello world
│ │
├─ 看到结果 │
│ │
└─ 结束 └─ 结束

三个关键边界:

1
2
3
4
5
6
7
8
边界 1:用户输入 → 程序参数(argv)
用户的世界和程序的世界在这里交接

边界 2:程序输出 → 屏幕文字
程序的世界和用户的世界在这里再次交接

边界 3:程序退出
一切结束,没有后续

无交互CLI的本质:两个世界只在开始和结束时各碰一次。


三、用户流程的完整路径

用户流程(完整):

1
2
3
4
5
6
7
8
1. 打开终端
2. 输入命令和参数
3. 按回车
4. 等待(屏幕显示或变化,或进度输出)
5. 看到结果
6. 决定下一步
7. 终端提示符重新出现
8. 用户输入下一个命令(或关闭终端)

用户流程和执行流的交界点只在两端:

1
用户 → 输入 → 程序 → 输出 → 用户

中间完全是程序的执行流,用户无法介入(执行流在交互形态下的变化见 06,第二节)。


四、无交互CLI的核心约束

1
2
3
4
5
6
7
8
9
graph LR
A["用户输入"] -->|"argv"| B["程序执行"]
B -->|"stdout/stderr"| C["用户看到结果"]
C -->|"结束"| D["程序退出"]

style A fill:#4a9eff,color:#fff
style B fill:#ff9f4a,color:#fff
style C fill:#4caf50,color:#fff
style D fill:#888,color:#fff

约束 1:没有会话状态

1
2
3
4
5
$ grep "hello" file1.txt
hello world
$ grep "hello" file2.txt
(no output)
$

两次 grep 之间没有关联——第二次不知道第一次搜了什么。每次调用都是独立的。

1
2
3
状态:无
记忆:无
上下文:只有当前这次调用的参数

约束 2:不能追问

程序不能问用户「你要搜哪个文件?」——它必须在启动时获得所有信息。

1
2
程序需要的全部信息 = 命令行参数(argv)
如果参数不够 → 报错退出,不能追问

约束 3:不能中途干预

程序运行期间用户无法干预——不能暂停、不能修改参数、不能跳过某一步。

1
用户输入后 → 失去控制权 → 等待结果 → 重新获得控制权

约束 4:输出是最终的

程序输出后就退出了——用户看到的就是最终结果,没有「刷新」「更新」的概念。


五、无交互CLI的用户流程模式

所有无交互CLI共享同一个用户流程模式:

1
输入命令 → 等待 → 看到结果 → 结束

不同的无交互CLI只是在「等待」期间做了不同的事:

1
2
3
4
grep:     搜索文件
gcc: 编译代码
ls: 列出目录
ffmpeg: 转换视频(可能有进度输出)

用户流程的结构完全相同,区别在程序执行流的内部。

无交互CLI的用户流程是一条直线——这是所有交互形态中最简单的。


六、这条直线对程序设计的影响

无交互CLI的直线结构决定了程序设计的方式:

1
2
3
4
5
1. 参数必须在启动时全部给定(没有运行时追问)
2. 程序必须有明确的退出码(0=成功,非0=失败)
3. 输出必须是最终的(stdout=正常结果,stderr=错误信息)
4. 程序应该是无状态的(每次调用独立)
5. 程序应该是幂等的(同样参数同样结果)

这些约束不是人为规定的,而是直线型用户流程的自然结果(控制流/错误流/状态流/反馈流在此形态下的形态见 06)。

当用户流程从直线变成循环时,这些约束就会被打破。 下一篇看有交互CLI——用户流程第一次变成了循环。