terminal-quest 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/bin/terminal-quest.js +2 -0
- package/dist/App.d.ts +2 -0
- package/dist/App.js +33 -0
- package/dist/components/HintBar.d.ts +9 -0
- package/dist/components/HintBar.js +11 -0
- package/dist/components/MenuItem.d.ts +9 -0
- package/dist/components/MenuItem.js +9 -0
- package/dist/components/ObjectivePanel.d.ts +8 -0
- package/dist/components/ObjectivePanel.js +10 -0
- package/dist/components/ProgressBar.d.ts +8 -0
- package/dist/components/ProgressBar.js +10 -0
- package/dist/components/TerminalOutput.d.ts +11 -0
- package/dist/components/TerminalOutput.js +25 -0
- package/dist/components/TerminalPrompt.d.ts +10 -0
- package/dist/components/TerminalPrompt.js +46 -0
- package/dist/data/commands-meta.d.ts +17 -0
- package/dist/data/commands-meta.js +256 -0
- package/dist/data/stories/00-beginner-pc.d.ts +3 -0
- package/dist/data/stories/00-beginner-pc.js +841 -0
- package/dist/data/stories/01-first-server.d.ts +3 -0
- package/dist/data/stories/01-first-server.js +364 -0
- package/dist/data/stories/02-messy-project.d.ts +3 -0
- package/dist/data/stories/02-messy-project.js +433 -0
- package/dist/data/stories/03-log-detective.d.ts +3 -0
- package/dist/data/stories/03-log-detective.js +291 -0
- package/dist/data/stories/04-deploy-day.d.ts +3 -0
- package/dist/data/stories/04-deploy-day.js +337 -0
- package/dist/data/stories/05-git-incident.d.ts +3 -0
- package/dist/data/stories/05-git-incident.js +534 -0
- package/dist/data/stories/06-pipe-master.d.ts +3 -0
- package/dist/data/stories/06-pipe-master.js +377 -0
- package/dist/data/stories/07-dangerous-commands.d.ts +3 -0
- package/dist/data/stories/07-dangerous-commands.js +411 -0
- package/dist/data/stories/index.d.ts +4 -0
- package/dist/data/stories/index.js +14 -0
- package/dist/data/stories/k1-treasure-hunt.d.ts +3 -0
- package/dist/data/stories/k1-treasure-hunt.js +815 -0
- package/dist/data/types.d.ts +97 -0
- package/dist/data/types.js +2 -0
- package/dist/engine/Achievements.d.ts +5 -0
- package/dist/engine/Achievements.js +93 -0
- package/dist/engine/CommandHandler.d.ts +17 -0
- package/dist/engine/CommandHandler.js +177 -0
- package/dist/engine/HintEngine.d.ts +10 -0
- package/dist/engine/HintEngine.js +26 -0
- package/dist/engine/MissionEngine.d.ts +17 -0
- package/dist/engine/MissionEngine.js +84 -0
- package/dist/engine/TabCompletion.d.ts +14 -0
- package/dist/engine/TabCompletion.js +93 -0
- package/dist/engine/VirtualFS.d.ts +33 -0
- package/dist/engine/VirtualFS.js +276 -0
- package/dist/engine/commands/cat.d.ts +4 -0
- package/dist/engine/commands/cat.js +18 -0
- package/dist/engine/commands/cd.d.ts +4 -0
- package/dist/engine/commands/cd.js +12 -0
- package/dist/engine/commands/chmod.d.ts +4 -0
- package/dist/engine/commands/chmod.js +98 -0
- package/dist/engine/commands/clear.d.ts +4 -0
- package/dist/engine/commands/clear.js +4 -0
- package/dist/engine/commands/cp.d.ts +4 -0
- package/dist/engine/commands/cp.js +26 -0
- package/dist/engine/commands/cut.d.ts +4 -0
- package/dist/engine/commands/cut.js +76 -0
- package/dist/engine/commands/echo.d.ts +4 -0
- package/dist/engine/commands/echo.js +4 -0
- package/dist/engine/commands/find.d.ts +4 -0
- package/dist/engine/commands/find.js +60 -0
- package/dist/engine/commands/git.d.ts +4 -0
- package/dist/engine/commands/git.js +510 -0
- package/dist/engine/commands/grep.d.ts +4 -0
- package/dist/engine/commands/grep.js +127 -0
- package/dist/engine/commands/head.d.ts +4 -0
- package/dist/engine/commands/head.js +59 -0
- package/dist/engine/commands/help.d.ts +4 -0
- package/dist/engine/commands/help.js +32 -0
- package/dist/engine/commands/hint.d.ts +4 -0
- package/dist/engine/commands/hint.js +4 -0
- package/dist/engine/commands/index.d.ts +8 -0
- package/dist/engine/commands/index.js +51 -0
- package/dist/engine/commands/ls.d.ts +4 -0
- package/dist/engine/commands/ls.js +50 -0
- package/dist/engine/commands/man.d.ts +4 -0
- package/dist/engine/commands/man.js +51 -0
- package/dist/engine/commands/mkdir.d.ts +4 -0
- package/dist/engine/commands/mkdir.js +31 -0
- package/dist/engine/commands/mv.d.ts +4 -0
- package/dist/engine/commands/mv.js +15 -0
- package/dist/engine/commands/pwd.d.ts +4 -0
- package/dist/engine/commands/pwd.js +4 -0
- package/dist/engine/commands/rm.d.ts +4 -0
- package/dist/engine/commands/rm.js +49 -0
- package/dist/engine/commands/sort.d.ts +4 -0
- package/dist/engine/commands/sort.js +100 -0
- package/dist/engine/commands/tail.d.ts +4 -0
- package/dist/engine/commands/tail.js +59 -0
- package/dist/engine/commands/touch.d.ts +4 -0
- package/dist/engine/commands/touch.js +18 -0
- package/dist/engine/commands/uniq.d.ts +4 -0
- package/dist/engine/commands/uniq.js +61 -0
- package/dist/engine/commands/wc.d.ts +4 -0
- package/dist/engine/commands/wc.js +67 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +6 -0
- package/dist/screens/MissionBriefScreen.d.ts +9 -0
- package/dist/screens/MissionBriefScreen.js +27 -0
- package/dist/screens/MissionCompleteScreen.d.ts +9 -0
- package/dist/screens/MissionCompleteScreen.js +30 -0
- package/dist/screens/ProgressScreen.d.ts +8 -0
- package/dist/screens/ProgressScreen.js +24 -0
- package/dist/screens/SettingsScreen.d.ts +8 -0
- package/dist/screens/SettingsScreen.js +45 -0
- package/dist/screens/StorySelectScreen.d.ts +8 -0
- package/dist/screens/StorySelectScreen.js +81 -0
- package/dist/screens/TerminalScreen.d.ts +12 -0
- package/dist/screens/TerminalScreen.js +150 -0
- package/dist/screens/TitleScreen.d.ts +7 -0
- package/dist/screens/TitleScreen.js +27 -0
- package/dist/state/GameState.d.ts +8 -0
- package/dist/state/GameState.js +12 -0
- package/dist/state/ProgressStore.d.ts +9 -0
- package/dist/state/ProgressStore.js +45 -0
- package/dist/state/useGameState.d.ts +11 -0
- package/dist/state/useGameState.js +92 -0
- package/dist/utils/ascii-art.d.ts +4 -0
- package/dist/utils/ascii-art.js +22 -0
- package/dist/utils/colors.d.ts +17 -0
- package/dist/utils/colors.js +17 -0
- package/dist/utils/text.d.ts +4 -0
- package/dist/utils/text.js +28 -0
- package/package.json +58 -0
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
const fileNames = Array.from({ length: 20 }, (_, i) => {
|
|
2
|
+
const num = String(i + 1).padStart(2, '0');
|
|
3
|
+
return `file${num}.txt`;
|
|
4
|
+
});
|
|
5
|
+
const fileChildren = {};
|
|
6
|
+
for (const name of fileNames) {
|
|
7
|
+
fileChildren[name] = {
|
|
8
|
+
type: 'file',
|
|
9
|
+
content: `Data content of ${name}\n`,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
const accessLogForPipe = [
|
|
13
|
+
'2024-01-15 08:00:01 [INFO] User login: admin',
|
|
14
|
+
'2024-01-15 08:05:10 [INFO] Request: GET /api/users',
|
|
15
|
+
'2024-01-15 08:10:22 [ERROR] Database connection timeout',
|
|
16
|
+
'2024-01-15 08:15:33 [INFO] Request: POST /api/data',
|
|
17
|
+
'2024-01-15 08:20:45 [ERROR] Failed to write to disk: permission denied',
|
|
18
|
+
'2024-01-15 08:25:00 [INFO] Cache cleared',
|
|
19
|
+
'2024-01-15 08:30:12 [INFO] Request: GET /api/status',
|
|
20
|
+
'2024-01-15 08:35:25 [ERROR] Memory allocation failed',
|
|
21
|
+
'2024-01-15 08:40:30 [INFO] Backup completed',
|
|
22
|
+
'2024-01-15 08:45:00 [INFO] Request: GET /api/health',
|
|
23
|
+
].join('\n');
|
|
24
|
+
const mission1FS = {
|
|
25
|
+
type: 'directory',
|
|
26
|
+
children: {
|
|
27
|
+
home: {
|
|
28
|
+
type: 'directory',
|
|
29
|
+
children: {
|
|
30
|
+
data: {
|
|
31
|
+
type: 'directory',
|
|
32
|
+
children: {
|
|
33
|
+
...fileChildren,
|
|
34
|
+
logs: {
|
|
35
|
+
type: 'directory',
|
|
36
|
+
children: {
|
|
37
|
+
'access.log': {
|
|
38
|
+
type: 'file',
|
|
39
|
+
content: accessLogForPipe,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
const salesCsvLines = [
|
|
50
|
+
'部門,金額',
|
|
51
|
+
'営業,150000',
|
|
52
|
+
'開発,200000',
|
|
53
|
+
'営業,180000',
|
|
54
|
+
'人事,120000',
|
|
55
|
+
'開発,250000',
|
|
56
|
+
'営業,160000',
|
|
57
|
+
'人事,130000',
|
|
58
|
+
'開発,220000',
|
|
59
|
+
'総務,100000',
|
|
60
|
+
'営業,170000',
|
|
61
|
+
'開発,210000',
|
|
62
|
+
'総務,110000',
|
|
63
|
+
'人事,125000',
|
|
64
|
+
'営業,190000',
|
|
65
|
+
'開発,230000',
|
|
66
|
+
'総務,105000',
|
|
67
|
+
'営業,175000',
|
|
68
|
+
'人事,135000',
|
|
69
|
+
'開発,240000',
|
|
70
|
+
].join('\n');
|
|
71
|
+
const mission2FS = {
|
|
72
|
+
type: 'directory',
|
|
73
|
+
children: {
|
|
74
|
+
home: {
|
|
75
|
+
type: 'directory',
|
|
76
|
+
children: {
|
|
77
|
+
data: {
|
|
78
|
+
type: 'directory',
|
|
79
|
+
children: {
|
|
80
|
+
'sales.csv': {
|
|
81
|
+
type: 'file',
|
|
82
|
+
content: salesCsvLines,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
const employeesCsvLines = [
|
|
91
|
+
'名前,部門,年齢',
|
|
92
|
+
'田中太郎,営業,28',
|
|
93
|
+
'鈴木花子,開発,32',
|
|
94
|
+
'佐藤一郎,人事,45',
|
|
95
|
+
'山田美咲,開発,26',
|
|
96
|
+
'伊藤健太,営業,38',
|
|
97
|
+
'渡辺由美,総務,29',
|
|
98
|
+
'中村大輔,開発,35',
|
|
99
|
+
'小林真理,人事,42',
|
|
100
|
+
'加藤翔太,営業,31',
|
|
101
|
+
'吉田恵子,総務,27',
|
|
102
|
+
].join('\n');
|
|
103
|
+
const mission3FS = {
|
|
104
|
+
type: 'directory',
|
|
105
|
+
children: {
|
|
106
|
+
home: {
|
|
107
|
+
type: 'directory',
|
|
108
|
+
children: {
|
|
109
|
+
data: {
|
|
110
|
+
type: 'directory',
|
|
111
|
+
children: {
|
|
112
|
+
'employees.csv': {
|
|
113
|
+
type: 'file',
|
|
114
|
+
content: employeesCsvLines,
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
const serverLogLines = [
|
|
123
|
+
'{"timestamp":"2024-01-15T08:00:01","level":"INFO","service":"web","message":"Server started"}',
|
|
124
|
+
'{"timestamp":"2024-01-15T08:00:05","level":"INFO","service":"api","message":"API ready"}',
|
|
125
|
+
'{"timestamp":"2024-01-15T08:01:10","level":"INFO","service":"db","message":"Connection pool initialized"}',
|
|
126
|
+
'{"timestamp":"2024-01-15T08:02:15","level":"ERROR","service":"web","message":"Template rendering failed"}',
|
|
127
|
+
'{"timestamp":"2024-01-15T08:03:20","level":"INFO","service":"api","message":"Request processed"}',
|
|
128
|
+
'{"timestamp":"2024-01-15T08:04:25","level":"INFO","service":"web","message":"Static files served"}',
|
|
129
|
+
'{"timestamp":"2024-01-15T08:05:30","level":"ERROR","service":"db","message":"Query timeout exceeded"}',
|
|
130
|
+
'{"timestamp":"2024-01-15T08:06:35","level":"INFO","service":"api","message":"Cache hit"}',
|
|
131
|
+
'{"timestamp":"2024-01-15T08:07:40","level":"INFO","service":"web","message":"Session created"}',
|
|
132
|
+
'{"timestamp":"2024-01-15T08:08:45","level":"ERROR","service":"api","message":"Rate limit exceeded"}',
|
|
133
|
+
'{"timestamp":"2024-01-15T08:09:50","level":"INFO","service":"db","message":"Backup started"}',
|
|
134
|
+
'{"timestamp":"2024-01-15T08:10:55","level":"INFO","service":"web","message":"Request processed"}',
|
|
135
|
+
'{"timestamp":"2024-01-15T08:12:00","level":"INFO","service":"api","message":"Health check OK"}',
|
|
136
|
+
'{"timestamp":"2024-01-15T08:13:05","level":"ERROR","service":"web","message":"CSS compilation error"}',
|
|
137
|
+
'{"timestamp":"2024-01-15T08:14:10","level":"INFO","service":"db","message":"Index rebuilt"}',
|
|
138
|
+
'{"timestamp":"2024-01-15T08:15:15","level":"INFO","service":"api","message":"Token refreshed"}',
|
|
139
|
+
'{"timestamp":"2024-01-15T08:16:20","level":"ERROR","service":"db","message":"Deadlock detected"}',
|
|
140
|
+
'{"timestamp":"2024-01-15T08:17:25","level":"INFO","service":"web","message":"Request processed"}',
|
|
141
|
+
'{"timestamp":"2024-01-15T08:18:30","level":"INFO","service":"api","message":"WebSocket connected"}',
|
|
142
|
+
'{"timestamp":"2024-01-15T08:19:35","level":"INFO","service":"db","message":"Replication sync"}',
|
|
143
|
+
'{"timestamp":"2024-01-15T08:20:40","level":"ERROR","service":"api","message":"Invalid JSON payload"}',
|
|
144
|
+
'{"timestamp":"2024-01-15T08:21:45","level":"INFO","service":"web","message":"Middleware loaded"}',
|
|
145
|
+
'{"timestamp":"2024-01-15T08:22:50","level":"INFO","service":"db","message":"Query optimized"}',
|
|
146
|
+
'{"timestamp":"2024-01-15T08:23:55","level":"ERROR","service":"web","message":"404 Not Found: /missing"}',
|
|
147
|
+
'{"timestamp":"2024-01-15T08:25:00","level":"INFO","service":"api","message":"Batch job started"}',
|
|
148
|
+
'{"timestamp":"2024-01-15T08:26:05","level":"INFO","service":"db","message":"Connection released"}',
|
|
149
|
+
'{"timestamp":"2024-01-15T08:27:10","level":"INFO","service":"web","message":"Gzip compression applied"}',
|
|
150
|
+
'{"timestamp":"2024-01-15T08:28:15","level":"ERROR","service":"db","message":"Foreign key constraint violation"}',
|
|
151
|
+
'{"timestamp":"2024-01-15T08:29:20","level":"INFO","service":"api","message":"Response cached"}',
|
|
152
|
+
'{"timestamp":"2024-01-15T08:30:25","level":"INFO","service":"web","message":"CORS headers set"}',
|
|
153
|
+
'{"timestamp":"2024-01-15T08:31:30","level":"ERROR","service":"api","message":"Service unavailable: upstream timeout"}',
|
|
154
|
+
'{"timestamp":"2024-01-15T08:32:35","level":"INFO","service":"db","message":"Vacuum completed"}',
|
|
155
|
+
'{"timestamp":"2024-01-15T08:33:40","level":"INFO","service":"web","message":"Request logged"}',
|
|
156
|
+
'{"timestamp":"2024-01-15T08:34:45","level":"INFO","service":"api","message":"Authentication passed"}',
|
|
157
|
+
'{"timestamp":"2024-01-15T08:35:50","level":"ERROR","service":"web","message":"Memory limit warning"}',
|
|
158
|
+
'{"timestamp":"2024-01-15T08:36:55","level":"INFO","service":"db","message":"Slow query logged"}',
|
|
159
|
+
'{"timestamp":"2024-01-15T08:38:00","level":"INFO","service":"api","message":"File uploaded"}',
|
|
160
|
+
'{"timestamp":"2024-01-15T08:39:05","level":"INFO","service":"web","message":"Template cached"}',
|
|
161
|
+
'{"timestamp":"2024-01-15T08:40:10","level":"ERROR","service":"db","message":"Connection pool exhausted"}',
|
|
162
|
+
'{"timestamp":"2024-01-15T08:41:15","level":"INFO","service":"api","message":"Email sent"}',
|
|
163
|
+
'{"timestamp":"2024-01-15T08:42:20","level":"INFO","service":"web","message":"Static cache cleared"}',
|
|
164
|
+
'{"timestamp":"2024-01-15T08:43:25","level":"ERROR","service":"api","message":"Validation error: missing field"}',
|
|
165
|
+
'{"timestamp":"2024-01-15T08:44:30","level":"INFO","service":"db","message":"Migration applied"}',
|
|
166
|
+
'{"timestamp":"2024-01-15T08:45:35","level":"INFO","service":"web","message":"Heartbeat OK"}',
|
|
167
|
+
'{"timestamp":"2024-01-15T08:46:40","level":"INFO","service":"api","message":"Rate limit reset"}',
|
|
168
|
+
'{"timestamp":"2024-01-15T08:47:45","level":"ERROR","service":"web","message":"SSL certificate expiring soon"}',
|
|
169
|
+
'{"timestamp":"2024-01-15T08:48:50","level":"INFO","service":"db","message":"Statistics updated"}',
|
|
170
|
+
'{"timestamp":"2024-01-15T08:49:55","level":"INFO","service":"api","message":"Graceful shutdown initiated"}',
|
|
171
|
+
'{"timestamp":"2024-01-15T08:51:00","level":"ERROR","service":"db","message":"Replication lag detected"}',
|
|
172
|
+
'{"timestamp":"2024-01-15T08:52:05","level":"INFO","service":"web","message":"Server stopped"}',
|
|
173
|
+
].join('\n');
|
|
174
|
+
const reportLogLines = [
|
|
175
|
+
'ERROR web Template rendering failed',
|
|
176
|
+
'ERROR db Query timeout exceeded',
|
|
177
|
+
'ERROR api Rate limit exceeded',
|
|
178
|
+
'INFO web Request processed',
|
|
179
|
+
'INFO api Health check OK',
|
|
180
|
+
'ERROR web CSS compilation error',
|
|
181
|
+
'ERROR db Deadlock detected',
|
|
182
|
+
'INFO db Backup started',
|
|
183
|
+
'ERROR api Invalid JSON payload',
|
|
184
|
+
'INFO web Static files served',
|
|
185
|
+
'ERROR web Memory limit warning',
|
|
186
|
+
'ERROR db Connection pool exhausted',
|
|
187
|
+
'INFO api Token refreshed',
|
|
188
|
+
'ERROR api Service unavailable',
|
|
189
|
+
'ERROR web SSL certificate expiring',
|
|
190
|
+
'INFO db Replication sync',
|
|
191
|
+
'ERROR db Foreign key violation',
|
|
192
|
+
'INFO web Heartbeat OK',
|
|
193
|
+
].join('\n');
|
|
194
|
+
const mission4FS = {
|
|
195
|
+
type: 'directory',
|
|
196
|
+
children: {
|
|
197
|
+
home: {
|
|
198
|
+
type: 'directory',
|
|
199
|
+
children: {
|
|
200
|
+
data: {
|
|
201
|
+
type: 'directory',
|
|
202
|
+
children: {
|
|
203
|
+
'server-log.txt': {
|
|
204
|
+
type: 'file',
|
|
205
|
+
content: serverLogLines,
|
|
206
|
+
},
|
|
207
|
+
'report.log': {
|
|
208
|
+
type: 'file',
|
|
209
|
+
content: reportLogLines,
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
export const story06 = {
|
|
218
|
+
id: 'story-06',
|
|
219
|
+
title: 'パイプの達人',
|
|
220
|
+
description: 'パイプ(|)を使ってコマンドを連携させ、複雑なデータ処理をこなそう。',
|
|
221
|
+
emoji: '\u{1F517}',
|
|
222
|
+
missions: [
|
|
223
|
+
{
|
|
224
|
+
id: 'mission-06-01',
|
|
225
|
+
title: 'パイプ入門',
|
|
226
|
+
description: 'パイプ(|)を使ってコマンドの出力を次のコマンドに渡そう。',
|
|
227
|
+
narrative: 'パイプ(|)を使うと、コマンドの出力を次のコマンドの入力にできる。',
|
|
228
|
+
initialCwd: '/home/data',
|
|
229
|
+
initialFS: mission1FS,
|
|
230
|
+
objectives: [
|
|
231
|
+
{
|
|
232
|
+
id: 'obj-06-01-01',
|
|
233
|
+
description: 'ファイル一覧の先頭5件を表示する',
|
|
234
|
+
checks: [{ type: 'output_contains', pattern: 'file05' }],
|
|
235
|
+
hints: [
|
|
236
|
+
{ level: 1, text: 'コマンドの出力を別のコマンドに渡す記号があります。' },
|
|
237
|
+
{ level: 2, text: 'ls の出力をパイプ(|)で head に渡します。head -n 5 で先頭5行を取得できます。' },
|
|
238
|
+
{ level: 3, text: '「ls | head -n 5」と入力してEnterを押してください。' },
|
|
239
|
+
],
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
id: 'obj-06-01-02',
|
|
243
|
+
description: 'ログから ERROR を含む行を抽出する',
|
|
244
|
+
checks: [
|
|
245
|
+
{ type: 'command_executed', command: 'grep' },
|
|
246
|
+
{ type: 'output_contains', pattern: 'ERROR' },
|
|
247
|
+
],
|
|
248
|
+
hints: [
|
|
249
|
+
{ level: 1, text: 'cat でファイルを表示し、パイプで grep に渡しましょう。' },
|
|
250
|
+
{ level: 2, text: 'cat と grep をパイプで繋ぎます。直接 grep にファイルを指定してもOKです。' },
|
|
251
|
+
{ level: 3, text: '「cat logs/access.log | grep ERROR」と入力してEnterを押してください。' },
|
|
252
|
+
],
|
|
253
|
+
},
|
|
254
|
+
],
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
id: 'mission-06-02',
|
|
258
|
+
title: 'データ加工',
|
|
259
|
+
description: 'sort と uniq、grep と wc をパイプで組み合わせてデータを分析しよう。',
|
|
260
|
+
narrative: 'データの集計と分析にパイプを活用しよう。',
|
|
261
|
+
initialCwd: '/home/data',
|
|
262
|
+
initialFS: mission2FS,
|
|
263
|
+
objectives: [
|
|
264
|
+
{
|
|
265
|
+
id: 'obj-06-02-01',
|
|
266
|
+
description: '部門の種類を確認する',
|
|
267
|
+
checks: [
|
|
268
|
+
{ type: 'command_executed', command: 'sort' },
|
|
269
|
+
{ type: 'output_contains', pattern: '\u55B6\u696D' },
|
|
270
|
+
],
|
|
271
|
+
hints: [
|
|
272
|
+
{ level: 1, text: 'CSVの特定の列を抽出して、重複を除去しましょう。' },
|
|
273
|
+
{ level: 2, text: 'cut -d, -f1 で部門列を抽出し、sort | uniq でユニークな値を取得できます。' },
|
|
274
|
+
{ level: 3, text: '「cut -d, -f1 sales.csv | sort | uniq」と入力してEnterを押してください。' },
|
|
275
|
+
],
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
id: 'obj-06-02-02',
|
|
279
|
+
description: 'データの件数を数える(20件)',
|
|
280
|
+
checks: [{ type: 'output_contains', pattern: '20' }],
|
|
281
|
+
hints: [
|
|
282
|
+
{ level: 1, text: '行数を数えるコマンドを使いましょう。' },
|
|
283
|
+
{ level: 2, text: 'wc -l コマンドでファイルの行数を数えられます。' },
|
|
284
|
+
{ level: 3, text: '「wc -l sales.csv」と入力してEnterを押してください。' },
|
|
285
|
+
],
|
|
286
|
+
},
|
|
287
|
+
],
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
id: 'mission-06-03',
|
|
291
|
+
title: 'フィールド抽出',
|
|
292
|
+
description: 'cut コマンドでCSVから特定のフィールドを抽出しよう。',
|
|
293
|
+
narrative: 'CSVデータから特定のフィールドを抽出して分析しよう。',
|
|
294
|
+
initialCwd: '/home/data',
|
|
295
|
+
newCommands: ['cut'],
|
|
296
|
+
initialFS: mission3FS,
|
|
297
|
+
objectives: [
|
|
298
|
+
{
|
|
299
|
+
id: 'obj-06-03-01',
|
|
300
|
+
description: '部門のフィールドだけを抽出する',
|
|
301
|
+
checks: [
|
|
302
|
+
{ type: 'command_executed', command: 'cut' },
|
|
303
|
+
{ type: 'output_contains', pattern: '\u90E8\u9580' },
|
|
304
|
+
],
|
|
305
|
+
hints: [
|
|
306
|
+
{ level: 1, text: 'CSVの特定の列を抽出するコマンドがあります。' },
|
|
307
|
+
{ level: 2, text: 'cut コマンドに -d(区切り文字)と -f(フィールド番号)を指定します。' },
|
|
308
|
+
{ level: 3, text: '「cut -d, -f2 employees.csv」と入力してEnterを押してください。' },
|
|
309
|
+
],
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
id: 'obj-06-03-02',
|
|
313
|
+
description: 'データを年齢でソートする',
|
|
314
|
+
checks: [{ type: 'command_executed', command: 'sort' }],
|
|
315
|
+
hints: [
|
|
316
|
+
{ level: 1, text: '数値でソートするオプションがあります。' },
|
|
317
|
+
{ level: 2, text: 'sort に -t(区切り文字)-k(フィールド)-n(数値ソート)を指定します。' },
|
|
318
|
+
{ level: 3, text: '「sort -t, -k3 -n employees.csv」と入力してEnterを押してください。' },
|
|
319
|
+
],
|
|
320
|
+
},
|
|
321
|
+
],
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
id: 'mission-06-04',
|
|
325
|
+
title: '総合演習',
|
|
326
|
+
description: '複数のコマンドをパイプで繋いで、データを抽出してファイルに保存しよう。',
|
|
327
|
+
narrative: '最終課題。複数のコマンドをパイプで繋いで、データから必要な情報を抽出し、ファイルに保存しよう。',
|
|
328
|
+
initialCwd: '/home/data',
|
|
329
|
+
initialFS: mission4FS,
|
|
330
|
+
objectives: [
|
|
331
|
+
{
|
|
332
|
+
id: 'obj-06-04-01',
|
|
333
|
+
description: 'ERROR ログだけ抽出してファイルに保存する',
|
|
334
|
+
checks: [
|
|
335
|
+
{ type: 'file_exists', path: '/home/data/errors.txt' },
|
|
336
|
+
{ type: 'file_contains', path: '/home/data/errors.txt', pattern: 'ERROR' },
|
|
337
|
+
],
|
|
338
|
+
hints: [
|
|
339
|
+
{ level: 1, text: 'grep で抽出した結果をリダイレクトでファイルに保存しましょう。' },
|
|
340
|
+
{ level: 2, text: 'grep コマンドの出力を > でファイルに書き込めます。' },
|
|
341
|
+
{ level: 3, text: '「grep ERROR server-log.txt > errors.txt」と入力してEnterを押してください。' },
|
|
342
|
+
],
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
id: 'obj-06-04-02',
|
|
346
|
+
description: 'report.log からサービス別ERROR件数を集計する(4段パイプ)',
|
|
347
|
+
checks: [
|
|
348
|
+
{ type: 'command_executed', command: 'uniq' },
|
|
349
|
+
{ type: 'output_contains', pattern: 'web' },
|
|
350
|
+
{ type: 'output_contains', pattern: 'db' },
|
|
351
|
+
],
|
|
352
|
+
hints: [
|
|
353
|
+
{ level: 1, text: 'ERROR行を抽出し、サービス名だけ取り出して集計しましょう。' },
|
|
354
|
+
{ level: 2, text: 'grep ERROR で抽出 → cut -d" " -f2 でサービス名 → sort → uniq -c で集計できます。' },
|
|
355
|
+
{ level: 3, text: '「grep ERROR report.log | cut -d" " -f2 | sort | uniq -c」と入力してEnterを押してください。' },
|
|
356
|
+
],
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
id: 'obj-06-04-03',
|
|
360
|
+
description: 'ERROR件数の多い順にTOP3を表示する(6段パイプ)',
|
|
361
|
+
checks: [
|
|
362
|
+
{ type: 'command_executed', command: 'head' },
|
|
363
|
+
{ type: 'output_contains', pattern: 'web' },
|
|
364
|
+
],
|
|
365
|
+
hints: [
|
|
366
|
+
{ level: 1, text: '前の集計結果をさらにソートして上位だけ取り出しましょう。' },
|
|
367
|
+
{ level: 2, text: '前の4段パイプの結果に | sort -rn | head -n 3 を追加すると上位3件が取れます。' },
|
|
368
|
+
{ level: 3, text: '「grep ERROR report.log | cut -d" " -f2 | sort | uniq -c | sort -rn | head -n 3」と入力してEnterを押してください。' },
|
|
369
|
+
],
|
|
370
|
+
},
|
|
371
|
+
],
|
|
372
|
+
},
|
|
373
|
+
],
|
|
374
|
+
unlockRequires: ['story-03'],
|
|
375
|
+
course: 'engineer',
|
|
376
|
+
};
|
|
377
|
+
//# sourceMappingURL=06-pipe-master.js.map
|