Skip to content

Commit afb5437

Browse files
committed
feat: Add comprehensive Bash 10th line extraction tutorial with visualizations
- Implement 3 correct solutions: sed, awk, and tail+head - Add detailed ASCII diagrams explaining each approach's execution flow - Include performance benchmarks (Runtime/Memory) for all methods - Document edge case handling for files with <10 lines - Fix incorrect head+tail approach and explain why it fails - Add comparison table of all solutions with pros/cons - Provide production-ready error handling examples Solutions: 1. sed -n '10p' (23ms, 3.85MB) - Most recommended 2. awk 'NR==10' (30ms, 3.92MB) - Most flexible 3. tail -n +10 | head -n 1 (27ms, 3.88MB) - Intuitive Key improvements: - Visual diagrams for each command's data flow - Correct handling of edge cases (files with <10 lines) - Explanation of why head -n 10 | tail -n 1 is incorrect - Japanese documentation for better accessibility
1 parent 4e0a35d commit afb5437

1 file changed

Lines changed: 390 additions & 0 deletions

File tree

Lines changed: 390 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,390 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "a2d8d7c3",
6+
"metadata": {},
7+
"source": [
8+
"# Bash Shellを用いた10行目の抽出問題\n",
9+
"\n",
10+
"この問題では、テキストファイルの10行目だけを出力する方法を解説します。3つの異なるアプローチと、それぞれの動作原理を図解付きで説明します。"
11+
]
12+
},
13+
{
14+
"cell_type": "code",
15+
"execution_count": null,
16+
"id": "896f0cc3",
17+
"metadata": {
18+
"vscode": {
19+
"languageId": "shellscript"
20+
}
21+
},
22+
"outputs": [],
23+
"source": [
24+
"#!/bin/bash\n",
25+
"\n",
26+
"# ========================================\n",
27+
"# 解法1: sed を使用する方法\n",
28+
"# ========================================\n",
29+
"# Analyze Complexity\n",
30+
"# Runtime 23 ms\n",
31+
"# Beats 69.41%\n",
32+
"# Memory 3.85 MB\n",
33+
"# Beats 91.20%\n",
34+
"\n",
35+
"echo \"=== 解法1: sed ===\"\n",
36+
"sed -n '10p' file.txt\n",
37+
"\n",
38+
"# 解説:\n",
39+
"# -n : デフォルトの出力を抑制\n",
40+
"# '10p' : 10行目のみを出力(print)\n",
41+
"\n",
42+
"\n",
43+
"# ========================================\n",
44+
"# 解法2: head と tail を組み合わせる方法\n",
45+
"# ========================================\n",
46+
"# Analyze Complexity\n",
47+
"# Runtime 27 ms\n",
48+
"# Beats 24.40%\n",
49+
"# Memory 3.88 MB\n",
50+
"# Beats 91.20%\n",
51+
"\n",
52+
"echo -e \"\\n=== 解法2: head + tail ===\"\n",
53+
"tail -n +10 file.txt | head -n 1\n",
54+
"\n",
55+
"# 解説:\n",
56+
"# head -n 10 : 最初の10行を取得\n",
57+
"# tail -n 1 : その中から最後の1行(=10行目)を取得\n",
58+
"\n",
59+
"\n",
60+
"# ========================================\n",
61+
"# 解法3: awk を使用する方法\n",
62+
"# ========================================\n",
63+
"# Analyze Complexity\n",
64+
"# Runtime 30 ms\n",
65+
"# Beats 7.19%\n",
66+
"# Memory 3.92 MB\n",
67+
"# Beats 52.52%\n",
68+
"\n",
69+
"echo -e \"\\n=== 解法3: awk ===\"\n",
70+
"awk 'NR==10' file.txt\n",
71+
"\n",
72+
"# 解説:\n",
73+
"# NR : 現在の行番号(Number of Records)\n",
74+
"# NR==10 : 行番号が10の時にその行を出力\n",
75+
"\n",
76+
"\n",
77+
"# ========================================\n",
78+
"# 補足: 10行未満の場合の処理\n",
79+
"# ========================================\n",
80+
"# Analyze Complexity\n",
81+
"# Runtime 26 ms\n",
82+
"# Beats 34.48%\n",
83+
"# Memory 3.94 MB\n",
84+
"# Beats 52.52%\n",
85+
"\n",
86+
"echo -e \"\\n=== 10行未満のファイルへの対応 ===\"\n",
87+
"\n",
88+
"# エラーチェック付きバージョン\n",
89+
"if [ $(wc -l < file.txt) -ge 10 ]; then\n",
90+
" sed -n '10p' file.txt\n",
91+
"else\n",
92+
" echo \"\"\n",
93+
"fi"
94+
]
95+
},
96+
{
97+
"cell_type": "markdown",
98+
"id": "b7bf7ad3",
99+
"metadata": {},
100+
"source": [
101+
"## 詳細な図解と解説\n",
102+
"\n",
103+
"### **解法1: `sed` を使用する方法**\n",
104+
"\n",
105+
"```bash\n",
106+
"sed -n '10p' file.txt\n",
107+
"```\n",
108+
"\n",
109+
"**動作原理の図解:**\n",
110+
"\n",
111+
"```\n",
112+
"file.txt sed -n '10p' 出力\n",
113+
"┌─────────┐ ┌──────────────┐ ┌──────────┐\n",
114+
"│ Line 1 │──┐ │ │ │ │\n",
115+
"│ Line 2 │ │ │ -n: 自動出力 │ │ │\n",
116+
"│ Line 3 │ │ │ OFF │ │ │\n",
117+
"│ Line 4 │ ├──→│ │────────→│ │\n",
118+
"│ Line 5 │ │ │ 10p: 10行目 │ │ │\n",
119+
"│ Line 6 │ │ │ のみ出力 │ │ │\n",
120+
"│ Line 7 │ │ │ │ │ │\n",
121+
"│ Line 8 │ │ │ │ │ │\n",
122+
"│ Line 9 │ │ │ │ │ │\n",
123+
"│ Line 10 │──┘ │ ✓ │ │ Line 10 │\n",
124+
"└─────────┘ └──────────────┘ └──────────┘\n",
125+
"```\n",
126+
"\n",
127+
"**特徴:**\n",
128+
"- `-n`: デフォルトの出力を抑制\n",
129+
"- `10p`: 10行目に到達したら出力(print)\n",
130+
"- **最もシンプルで効率的**\n",
131+
"\n",
132+
"---\n",
133+
"\n",
134+
"### **解法2: `head` と `tail` の組み合わせ**\n",
135+
"\n",
136+
"```bash\n",
137+
"head -n 10 file.txt | tail -n 1\n",
138+
"```\n",
139+
"\n",
140+
"**動作原理の図解:**\n",
141+
"\n",
142+
"```\n",
143+
"file.txt head -n 10 tail -n 1 出力\n",
144+
"┌─────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐\n",
145+
"│ Line 1 │ │ Line 1 │ │ │ │ │\n",
146+
"│ Line 2 │ │ Line 2 │ │ │ │ │\n",
147+
"│ Line 3 │ │ Line 3 │ │ │ │ │\n",
148+
"│ Line 4 │───→│ Line 4 │ │ │ │ │\n",
149+
"│ Line 5 │ │ Line 5 │ │ │ │ │\n",
150+
"│ Line 6 │ │ Line 6 │──────→│ 最後の1行 │───→│ Line 10 │\n",
151+
"│ Line 7 │ │ Line 7 │ │ を取得 │ │ │\n",
152+
"│ Line 8 │ │ Line 8 │ │ │ │ │\n",
153+
"│ Line 9 │ │ Line 9 │ │ ✓ │ │ │\n",
154+
"│ Line 10 │ │ Line 10 │ │ Line 10 │ │ │\n",
155+
"│ Line 11 │ └──────────┘ └──────────┘ └──────────┘\n",
156+
"│ Line 12 │ ↑ ここまで\n",
157+
"└─────────┘\n",
158+
"```\n",
159+
"\n",
160+
"**処理の流れ:**\n",
161+
"1. `head -n 10`: 最初の10行を抽出\n",
162+
"2. `tail -n 1`: その中から最後の1行(つまり元の10行目)を取得\n",
163+
"\n",
164+
"**特徴:**\n",
165+
"- 直感的で理解しやすい\n",
166+
"- 2つのコマンドを組み合わせるため、やや冗長\n",
167+
"\n",
168+
"---\n",
169+
"\n",
170+
"### **解法3: `awk` を使用する方法**\n",
171+
"\n",
172+
"```bash\n",
173+
"awk 'NR==10' file.txt\n",
174+
"```\n",
175+
"\n",
176+
"**動作原理の図解:**\n",
177+
"\n",
178+
"```\n",
179+
"file.txt awk 'NR==10' 出力\n",
180+
"┌─────────┐ ┌───────────────────┐ ┌──────────┐\n",
181+
"│ Line 1 │ NR=1 ──→ │ NR==10? No │ │ │\n",
182+
"│ Line 2 │ NR=2 ──→ │ NR==10? No │ │ │\n",
183+
"│ Line 3 │ NR=3 ──→ │ NR==10? No │ │ │\n",
184+
"│ Line 4 │ NR=4 ──→ │ NR==10? No │ │ │\n",
185+
"│ Line 5 │ NR=5 ──→ │ NR==10? No │────────→│ │\n",
186+
"│ Line 6 │ NR=6 ──→ │ NR==10? No │ │ │\n",
187+
"│ Line 7 │ NR=7 ──→ │ NR==10? No │ │ │\n",
188+
"│ Line 8 │ NR=8 ──→ │ NR==10? No │ │ │\n",
189+
"│ Line 9 │ NR=9 ──→ │ NR==10? No │ │ │\n",
190+
"│ Line 10 │ NR=10 ──→ │ NR==10? Yes! ✓ │ │ Line 10 │\n",
191+
"└─────────┘ └───────────────────┘ └──────────┘\n",
192+
"```\n",
193+
"\n",
194+
"**特徴:**\n",
195+
"- `NR` (Number of Records): 現在の行番号を保持する変数\n",
196+
"- 条件が真の時のみ行を出力(デフォルト動作)\n",
197+
"- **テキスト処理に強力で柔軟性が高い**\n",
198+
"\n",
199+
"---\n",
200+
"\n",
201+
"## **10行未満のファイルへの対応**\n",
202+
"\n",
203+
"ファイルが10行未満の場合の動作比較:\n",
204+
"\n",
205+
"```\n",
206+
"5行のファイルの場合:\n",
207+
"\n",
208+
"┌─────────┐\n",
209+
"│ Line 1 │\n",
210+
"│ Line 2 │\n",
211+
"│ Line 3 │ ← 5行しかない\n",
212+
"│ Line 4 │\n",
213+
"│ Line 5 │\n",
214+
"└─────────┘\n",
215+
"\n",
216+
"sed -n '10p' → 何も出力しない\n",
217+
"head -n 10 | tail -n 1 → Line 5 を出力\n",
218+
"awk 'NR==10' → 何も出力しない\n",
219+
"```\n",
220+
"\n",
221+
"**エラーチェック付きバージョン:**\n",
222+
"\n",
223+
"```bash\n",
224+
"# 行数を確認してから処理\n",
225+
"if [ $(wc -l < file.txt) -ge 10 ]; then\n",
226+
" sed -n '10p' file.txt\n",
227+
"else\n",
228+
" echo \"エラー: ファイルが10行未満です\" >&2\n",
229+
"fi\n",
230+
"```\n",
231+
"\n",
232+
"---\n",
233+
"\n",
234+
"## **各解法の比較表**\n",
235+
"\n",
236+
"| 解法 | コマンド | 長所 | 短所 | 10行未満の動作 |\n",
237+
"|------|----------|------|------|----------------|\n",
238+
"| **sed** | `sed -n '10p'` | シンプル、高速 | sed文法の知識が必要 | 何も出力しない |\n",
239+
"| **head+tail** | `head -n 10 \\| tail -n 1` | 直感的 | 2つのプロセスが必要 | 最終行を出力 |\n",
240+
"| **awk** | `awk 'NR==10'` | 柔軟性が高い | やや複雑 | 何も出力しない |\n",
241+
"\n",
242+
"---\n",
243+
"\n",
244+
"## **推奨される解法**\n",
245+
"\n",
246+
"**最もシンプルで効率的:** `sed -n '10p' file.txt`\n",
247+
"\n",
248+
"これが最も一般的で、多くの場合に推奨される方法です!\n",
249+
"\n",
250+
"ご指摘ありがとうございます!問題を特定しました。\n",
251+
"\n",
252+
"## **問題点の分析**\n",
253+
"\n",
254+
"ファイルが**9行しかない**場合、`head -n 10`は9行すべてを出力し、`tail -n 1`はその最後の行(9行目)を出力してしまいます。\n",
255+
"\n",
256+
"### **動作の図解**\n",
257+
"\n",
258+
"```\n",
259+
"file.txt (9行) head -n 10 tail -n 1 出力\n",
260+
"┌─────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐\n",
261+
"│ 1 │ │ 1 │ │ │ │ │\n",
262+
"│ 2 │ │ 2 │ │ │ │ │\n",
263+
"│ 3 │ │ 3 │ │ │ │ │\n",
264+
"│ 4 │──────→ 4 │ │ │ │ │\n",
265+
"│ 5 │ │ 5 │──────→ 最後の1行 │────→ 9 │\n",
266+
"│ 6 │ │ 6 │ │ を取得 │ │ │\n",
267+
"│ 7 │ │ 7 │ │ ✓ │ │ ✗ 誤り! │\n",
268+
"│ 8 │ │ 8 │ │ 9 │ │ │\n",
269+
"│ 9 │ │ 9 │ │ │ │ │\n",
270+
"└─────────┘ └──────────┘ └──────────┘ └──────────┘\n",
271+
" 9行しかない → 9行出力 → 9を出力\n",
272+
"\n",
273+
"期待される出力: 何も出力しない(10行目は存在しない)\n",
274+
"実際の出力: 9\n",
275+
"```\n",
276+
"\n",
277+
"## **正しい解法**## **3つの正しい解法**\n",
278+
"\n",
279+
"### **解法1: `sed -n '10p'`(最も推奨)**\n",
280+
"\n",
281+
"```bash\n",
282+
"sed -n '10p' file.txt\n",
283+
"```\n",
284+
"\n",
285+
"✅ **正しい動作:**\n",
286+
"- 10行ある場合: 10行目を出力\n",
287+
"- 9行しかない場合: 何も出力しない\n",
288+
"\n",
289+
"---\n",
290+
"\n",
291+
"### **解法2: `awk 'NR==10'`(推奨)**\n",
292+
"\n",
293+
"```bash\n",
294+
"awk 'NR==10' file.txt\n",
295+
"```\n",
296+
"\n",
297+
"✅ **正しい動作:**\n",
298+
"- 10行ある場合: 10行目を出力\n",
299+
"- 9行しかない場合: 何も出力しない\n",
300+
"\n",
301+
"---\n",
302+
"\n",
303+
"### **解法3: `tail -n +10 | head -n 1`(推奨)**\n",
304+
"\n",
305+
"```bash\n",
306+
"tail -n +10 file.txt | head -n 1\n",
307+
"```\n",
308+
"\n",
309+
"**動作原理の図解:**\n",
310+
"\n",
311+
"```\n",
312+
"file.txt (9行) tail -n +10 head -n 1 出力\n",
313+
"┌─────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐\n",
314+
"│ 1 │ │ │ │ │ │ │\n",
315+
"│ 2 │ │ │ │ │ │ │\n",
316+
"│ 3 │ │ │ │ │ │ │\n",
317+
"│ 4 │ │ │ │ │ │ │\n",
318+
"│ 5 │ │ (空) │──────→ (空) │────→ (空) │\n",
319+
"│ 6 │ │ │ │ │ │ │\n",
320+
"│ 7 │ │ │ │ │ │ │\n",
321+
"│ 8 │ │ │ │ │ │ │\n",
322+
"│ 9 │ │ │ │ │ │ │\n",
323+
"└─────────┘ └──────────┘ └──────────┘ └──────────┘\n",
324+
" 10行目以降がない → 何も出力しない ✓\n",
325+
"\n",
326+
"\n",
327+
"file.txt (10行) tail -n +10 head -n 1 出力\n",
328+
"┌─────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐\n",
329+
"│ 1 │ │ │ │ │ │ │\n",
330+
"│ 2 │ │ │ │ │ │ │\n",
331+
"│ 3 │ │ │ │ ✓ │ │ │\n",
332+
"│ 4 │ │ 10 │──────→ 10 │────→ 10 │\n",
333+
"│ 5 │ │ │ │ │ │ │\n",
334+
"│ 6 │ │ │ │ │ │ │\n",
335+
"│ 7 │ │ │ │ │ │ │\n",
336+
"│ 8 │ │ │ │ │ │ │\n",
337+
"│ 9 │ │ │ │ │ │ │\n",
338+
"│ 10 │ │ │ │ │ │ │\n",
339+
"└─────────┘ └──────────┘ └──────────┘ └──────────┘\n",
340+
"```\n",
341+
"\n",
342+
"✅ **正しい動作:**\n",
343+
"- `tail -n +10`: 10行目から最後まで取得(+10は「10行目から」の意味)\n",
344+
"- `head -n 1`: その最初の1行を取得\n",
345+
"\n",
346+
"---\n",
347+
"\n",
348+
"## **なぜ `head -n 10 | tail -n 1` は間違いなのか**\n",
349+
"\n",
350+
"```\n",
351+
"❌ 間違った解法の動作:\n",
352+
"\n",
353+
"9行のファイル:\n",
354+
"1. head -n 10 → 9行すべてを出力(10行ないので9行しか取れない)\n",
355+
"2. tail -n 1 → その最後の1行 = 9行目を出力\n",
356+
"結果: 9 が出力される(誤り)\n",
357+
"\n",
358+
"10行のファイル:\n",
359+
"1. head -n 10 → 10行を出力\n",
360+
"2. tail -n 1 → その最後の1行 = 10行目を出力\n",
361+
"結果: 10 が出力される(正しい)\n",
362+
"```\n",
363+
"\n",
364+
"## **正解のまとめ**\n",
365+
"\n",
366+
"LeetCode/オンラインジャッジで正解する解法:\n",
367+
"\n",
368+
"```bash\n",
369+
"# 解法1(最もシンプル)\n",
370+
"sed -n '10p' file.txt\n",
371+
"\n",
372+
"# 解法2(汎用性が高い)\n",
373+
"awk 'NR==10' file.txt\n",
374+
"\n",
375+
"# 解法3(tailの+記法を使用)\n",
376+
"tail -n +10 file.txt | head -n 1\n",
377+
"```\n",
378+
"\n",
379+
"これらはすべて、ファイルが10行未満の場合は**何も出力しない**ため、テストケースをすべてパスします!"
380+
]
381+
}
382+
],
383+
"metadata": {
384+
"language_info": {
385+
"name": "python"
386+
}
387+
},
388+
"nbformat": 4,
389+
"nbformat_minor": 5
390+
}

0 commit comments

Comments
 (0)