Repository navigation
Expand file tree
/
Copy pathknowledge.py
More file actions
175 lines (164 loc) · 15 KB
/
Copy pathknowledge.py
File metadata and controls
175 lines (164 loc) · 15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
"""Scene-independent teaching concepts, evidence categories and review exercises.
No session answers, paths, shell history or model calls belong in this module.
"""
def concept(title, note, explanation, hints, question, choices, answer):
return dict(title=title, note=note, explanation=explanation, hints=hints,
question=question, choices=choices, answer=answer)
CONCEPTS = {
'paths': concept('工作目录与路径', 'navigation',
'相对路径从当前工作目录出发,绝对路径从 / 出发;.. 表示父目录。路径还区分大小写。',
['先确认你当前所在的目录,再对照任务要求的位置。',
'用 pwd 观察当前目录;相对路径要从这个位置逐层解释。',
'观察骨架:pwd。把输出路径与你期望的位置比较,再决定如何导航。'],
'当前目录是 /home/lin/notes,../draft 指向哪里?',
['A. /home/lin/draft', 'B. /home/lin/notes/draft', 'C. /draft'], 'A'),
'hidden': concept('隐藏文件与目录枚举', 'ls',
'名称以点号开头的项目默认不被 ls 显示,ls -a 才包含它们;隐藏不等于禁止访问。',
['核对观察范围是否包括隐藏项目。',
'ls 的 -a 选项会显示点号开头的名称,目录和文件都可能隐藏。',
'观察骨架:ls -a <待观察目录>。尖括号中的目录由你确定。'],
'普通 ls 没显示 .settings,能否据此断定它不存在?',
['A. 能', 'B. 不能,应检查隐藏项目', 'C. 它一定没有读取权限'], 'B'),
'mkdir': concept('目录创建与父目录', 'mkdir',
'创建目录需要正确的目标路径;mkdir -p 可补齐缺少的父目录,但不能修正写错的位置。',
['检查目标及其父级分别是文件、目录,还是尚不存在。',
'先观察父目录;mkdir 创建目录,-p 处理缺少的父级。',
'操作骨架:mkdir -p <你确认的目录路径>。执行前先核对当前位置。'],
'父目录 notes 尚不存在,mkdir -p notes/day1 会怎样?',
['A. 只创建 day1', 'B. 生成文本文件', 'C. 创建 notes 和其中的 day1 目录'], 'C'),
'copy': concept('完整复制与目标层级', 'cp',
'复制目录需递归处理;cp -a 尽量保留属性。目标是否已存在会影响层级,* 默认遗漏隐藏项。',
['比较原件与备份的目录层级、隐藏项和子目录。',
'用 ls -la 观察两侧;注意目标已存在时,复制整个目录可能再套一层。',
'观察骨架:ls -la <备份目录>。先确认直接子项是否与原件对应。'],
'cp notes/* backup/ 为什么可能漏掉 .settings?',
['A. 默认的 * 不匹配名称开头的点号', 'B. cp 永远不能复制隐藏文件', 'C. 文件名不能以点号开头'], 'A'),
'move': concept('移动与重命名', 'mv',
'mv 移动或改名后原路径应消失;cp 则保留原件。目标为已有目录时会把对象放入目录内。',
['比较任务要求的源位置和目标位置,检查是否仍有原件。',
'用 ls 分别观察两处;区分复制、移动,以及目标为目录或新文件名的情况。',
'观察骨架:ls <源位置> <目标位置>。先确认文件实际落在哪里。'],
'要求把 draft.txt 改名为 final.txt,哪种操作符合语义?',
['A. cp 后保留两个文件', 'B. mv,原名称不再存在', 'C. mkdir final.txt'], 'B'),
'glob': concept('通配符与删除范围', 'glob',
'Bash 先展开未加引号的 *,再交给命令;* 可匹配零个字符,默认不包含隐藏名称,也不跨越 /。',
['核对要删除和必须保留的名称规则。',
'先用 ls 预览匹配范围;共同前缀、后缀和隐藏项都影响选择。',
'观察骨架:ls <待核对的匹配模式>。仅预览,确认范围后再决定操作。'],
'note-*.txt 能匹配 note-.txt 吗?',
['A. 不能,* 至少匹配一个字符', 'B. 只能匹配目录', 'C. 能,* 可以匹配零个字符'], 'C'),
'archive_read': concept('归档读取与解包位置', 'tar',
'归档内保存成员路径。解包后的路径由解包目录和成员路径共同决定;列清单不会提取文件。',
['比较归档中的成员路径与当前恢复目录的结构。',
'tar -t 用于列清单,-x 才提取;-C 指定操作目录。',
'观察骨架:tar -tzf <归档文件>。先读成员名称,再判断提取位置。'],
'包内是 docs/readme.txt,解到 notes 后文件在哪里?',
['A. notes/docs/readme.txt', 'B. notes/readme.txt', 'C. docs/notes/readme.txt'], 'A'),
'logs': concept('日志时序与字段含义', 'tail',
'末尾一行不一定是最新有效业务记录;应同时核对时间顺序、记录类型及字段含义。',
['区分状态消息和有效业务记录,再检查它们的先后顺序。',
'tail -n 可以观察末尾若干行;不要只凭最后一行或首次出现的值判断。',
'观察骨架:tail -n <行数> <日志文件>。只选符合任务规则的记录。'],
'日志依次为 READY value=old、READY value=new、HEARTBEAT,最新 READY 的值是什么?',
['A. old', 'B. new', 'C. HEARTBEAT'], 'B'),
'config': concept('配置语法、字段与唯一性', 'vim',
'KEY=value 配置要分别核对键、值和重复项。修改了某一行,不代表其他行和生效文件也已正确。',
['按字段检查格式、重复项和取值来源。',
'用 cat 观察已保存的文本;键名和值含义不同,重复字段可能造成歧义。',
'观察骨架:cat <配置文件>。逐行核对 KEY=value,不直接猜测值。'],
'配置中出现两行相同的键,为什么应检查?',
['A. 重复能提高可靠性', 'B. 键名必须全是数字', 'C. 重复键可能让配置含义产生歧义'], 'C'),
'editing': concept('编辑、保存与磁盘文件', 'vim',
'编辑器缓冲区与磁盘文件不是同一个状态;Vim 中 Esc 回普通模式,:w 保存,:q! 放弃未保存修改。',
['核对你编辑的是哪个文件,以及修改是否已经保存。',
'Vim 的插入、普通和命令行模式用途不同;退出并不一定保存。',
'观察骨架:cat <刚编辑的文件>。核对磁盘内容是否包含你的修改。'],
'Vim 修改后用 :q! 退出,未保存的修改会怎样?',
['A. 被放弃', 'B. 自动保存', 'C. 自动存入所有同名文件'], 'A'),
'permissions': concept('权限位与最小权限', 'chmod',
'权限分别作用于所有者、组和其他人;r/w/x 含义不同,目录的 x 表示可穿越。配置通常不需要执行权限。',
['区分需要读取的配置与需要执行的脚本,检查各类用户的权限。',
'ls -l 显示权限;chmod 可按所有者、组、其他人分别设置。不要用全部放开来消除报错。',
'观察骨架:ls -l <待检查对象>。逐组解释 r、w、x,再对照要求。'],
'普通文件权限 640 表示什么?',
['A. 所有人可执行', 'B. 所有者读写、组只读、其他人无权限', 'C. 所有者只读、其他人读写'], 'B'),
'execution': concept('脚本启动与执行结果', 'chmod',
'文件存在不等于已经执行;直接运行脚本需要可执行权限和正确路径,应结合执行后的结果确认。',
['区分脚本准备完成和脚本实际运行完成。',
'观察脚本权限和运行后的产物;./ 表示当前目录中的程序。',
'观察骨架:ls -l <脚本路径>。确认对象和权限,再按任务自行执行。'],
'给脚本加上执行权限,是否就代表它已经运行?',
['A. 是', 'B. 只要文件存在就是运行中', 'C. 否,还需要执行并观察结果'], 'C'),
'process': concept('进程身份与生命周期', 'top',
'PID 只标识当前进程,退出后可能被复用;需结合进程名、归属与存活状态确认,旧观察可能已过时。',
['确认目标仍在运行,再核对身份和进程编号。',
'在 top 中区分 PID 与 COMMAND;进程结束后旧编号不能继续代表它。',
'观察骨架:top。核对当前列表中的身份,按 q 返回终端。'],
'昨天记下的 PID 今天一定仍指向同一进程吗?',
['A. 不一定,进程会结束且 PID 可能复用', 'B. 一定', 'C. PID 就是文件名'], 'A'),
'archive_build': concept('交付归档与内容快照', 'tar',
'归档是创建时的内容和权限快照;修改外部文件后要重新生成。归档成员路径与终端当前路径需要区分。',
['核对你交付的是最新的包,以及包内层级、内容和权限。',
'tar -tvzf 可观察成员及权限;修改源文件不会同步修改旧包。',
'观察骨架:tar -tvzf <交付包>。核对清单,再决定是否重新打包。'],
'打包后修改源文件,旧归档内容会自动改变吗?',
['A. 会', 'B. 不会,应重新生成并检查', 'C. 只有改权限才会自动改变'], 'B'),
'integrity': concept('原件保护与内容一致性', 'cp',
'名称相同并不保证内容相同;备份应保持原件完整,恢复前也应保留当前现场。',
['区分原件、备份、工作副本,确认哪些内容必须保留。',
'对照任务中的保全要求;文件缺失与内容被改动是不同的现象。',
'观察骨架:ls -la <原件目录>。先确认对象,误操作时了解 lab repair 的备份与恢复范围。'],
'两个文件名称相同,是否就能证明内容一致?',
['A. 能', 'B. 文件越大越可靠', 'C. 不能,还需核对内容'], 'C'),
}
PHASE_CONCEPTS = {
1: ['paths', 'hidden', 'mkdir'], 2: ['copy', 'hidden', 'integrity'],
3: ['move', 'glob', 'integrity'], 4: ['archive_read', 'paths'],
5: ['logs'], 6: ['config', 'editing', 'logs'],
7: ['permissions', 'execution', 'config'], 8: ['process'],
9: ['archive_build', 'config', 'permissions', 'copy', 'integrity'],
}
# A category describes an observation, never a proven mental misconception.
ISSUES = {
'location': ('提交位置与要求不符', ['paths'], ['当前目录不同', '相对路径起点理解有偏差']),
'directory': ('目标目录未就绪', ['mkdir', 'paths'], ['尚未创建', '创建位置或对象类型不同']),
'beacon': ('隐藏项目识别未完成', ['hidden'], ['尚未观察隐藏项目', '读到的名称或输入有误']),
'backup': ('备份不完整或内容不同', ['copy', 'hidden', 'integrity'], ['备份尚未完成', '多套目录或遗漏隐藏项、子目录', '内容被改动']),
'original': ('应保留的原件缺失或改变', ['integrity', 'copy'], ['原件被移动', '原件被删除或修改']),
'move': ('移动或改名结果不符', ['move', 'paths'], ['仅复制而未移动', '目标名称或位置不同']),
'cleanup': ('清理目标仍存在', ['glob'], ['尚未清理', '匹配范围遗漏或引号阻止展开']),
'preserve': ('应保留的文件缺失或改变', ['glob', 'integrity'], ['匹配范围过宽', '误删或误改了保留对象']),
'seal': ('归档信息识别不符', ['archive_read'], ['未读取正确成员', '提取位置或输入有误']),
'extraction': ('解包结果缺失或不同', ['archive_read', 'paths'], ['只列清单而未提取', '提取目录或层级不同', '提取后被改动']),
'log_record': ('日志记录选择或输入不符', ['logs'], ['选择了旧记录或状态消息', '字段含义混淆', '输入笔误']),
'config_format': ('配置行格式不符', ['config', 'editing'], ['缺少分隔符', '编辑时残留了文字']),
'config_duplicate': ('配置字段重复', ['config', 'editing'], ['新增字段时未替换旧字段', '重复粘贴']),
'config_value': ('配置字段值不符', ['config', 'logs', 'editing'], ['字段或值来源有误', '修改未保存或编辑了其他文件']),
'config_keys': ('配置字段集合不符', ['config'], ['存在多余字段', '键名拼写有误']),
'config_file': ('配置文件未就绪', ['editing', 'paths'], ['文件未保存到目标路径', '文件缺失或对象类型不同']),
'script': ('启动脚本缺失或被修改', ['integrity', 'execution'], ['脚本被覆盖', '文件放置或恢复不完整']),
'permissions': ('文件权限与要求不符', ['permissions'], ['尚未设置', '改了其他对象或混淆了权限位']),
'receipt': ('启动结果尚未满足', ['execution', 'permissions'], ['尚未执行', '执行失败或结果被改动']),
'process_absent': ('目标进程未运行或已结束', ['process'], ['尚未启动', '进程已超时或退出']),
'process_identity': ('提交的进程编号不匹配', ['process'], ['看错列或进程', '记录过时', '输入笔误']),
'archive_missing': ('交付归档尚未就绪', ['archive_build', 'paths'], ['尚未创建', '归档位置或名称不同']),
'archive_layout': ('归档成员或路径结构不符', ['archive_build'], ['打包起点不同', '包含多余、重复或特殊成员', '遗漏所需成员']),
'archive_content': ('归档内内容不符', ['archive_build', 'integrity'], ['打包了其他文件', '外部文件修改后未重新打包']),
'archive_permissions': ('归档内权限不符', ['archive_build', 'permissions'], ['源文件权限不符', '修改权限后未重新打包']),
'archive_format': ('归档格式无法读取', ['archive_read', 'archive_build'], ['文件不是预期压缩格式', '归档不完整或损坏']),
'file': ('文件缺失、类型或内容不符', ['paths', 'integrity'], ['位置或名称不同', '内容改变或尚未准备']),
'access': ('文件或目录无法访问', ['permissions', 'paths'], ['对象或父目录权限不足', '路径不正确']),
'path_type': ('路径包含不支持的对象', ['paths'], ['把普通文件当成目录', '使用了符号链接或其他对象']),
'encoding': ('文本编码无法读取', ['editing'], ['文件不是 UTF-8 文本', '误把其他格式当成文本']),
'unknown': ('当前检查未满足', [], ['证据不足,需要先观察当前任务与现场']),
}
def diagnosis(code, phase):
code = code if code in ISSUES else 'unknown'
title, topics, causes = ISSUES[code]
return dict(code=code, observation=title, concepts=topics or PHASE_CONCEPTS[phase],
possible_causes=list(causes), certainty='观察到结果;原因待核实')
def feedback(item):
titles = '、'.join(CONCEPTS[k]['title'] for k in item['concepts'])
evidence = ''.join('\n操作依据:' + text for text in item.get('evidence', []))
return ('关联知识:' + titles + evidence + '\n可能原因(待核实):' + ';'.join(item['possible_causes'])
+ '\n下一步:' + CONCEPTS[item['concepts'][0]]['hints'][0])