-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathpython-script.html
More file actions
92 lines (75 loc) · 4.92 KB
/
python-script.html
File metadata and controls
92 lines (75 loc) · 4.92 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
<html>
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<head>
<title>
leontrolski - cheeky Python shell script
</title>
<style>
body {margin: 5% auto; background: #fff7f7; color: #444444; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; font-size: 16px; line-height: 1.8; max-width: 63%;}
@media screen and (max-width: 800px) {body {font-size: 14px; line-height: 1.4; max-width: 90%;}}
pre {width: 100%; border-top: 3px solid gray; border-bottom: 3px solid gray;}
a {border-bottom: 1px solid #444444; color: #444444; text-decoration: none; text-shadow: 0 1px 0 #ffffff; }
a:hover {border-bottom: 0;}
.inline {background: #b3b2b226; padding-left: 0.3em; padding-right: 0.3em; white-space: nowrap;}
blockquote {font-style: italic;color:black;background-color:#f2f2f2;padding:2em;}
details {border-bottom:solid 5px gray;}
</style>
<link href="https://unpkg.com/prism-themes@1.9.0/themes/prism-darcula.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/components/prism-core.min.js">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/plugins/autoloader/prism-autoloader.min.js">
</script>
</head>
<body>
<a href="index.html">
<img src="pic.png" style="height:2em">
⇦
</a>
<p><i>2025-07-16</i></p>
<h1>
Cheeky Python shell script
</h1>
<p>Bash has so many gotchas (the <a href="https://til.codeinthehole.com/posts/that-while-read-loops-in-bash-dont-read-lines-with-no-new-line-character/">most recent one I've learnt</a>) that some people recommend jumping to Python at some complexity threshold. One of those people is me, and I'd set the threshold pretty low. </p>
<p>Assuming you have <a href="https://docs.astral.sh/uv/">uv</a> installed (you should), the new <a href="https://docs.astral.sh/uv/guides/scripts/">scripts directives</a> make the jump to Python even easier than before.</p>
<p>Here's an example script with:</p>
<ul>
<li>Nice argument handling via <a href="https://github.com/fastapi/typer">typer</a> - try <code>--help</code></li>
<li>Some globbing</li>
<li>Some regex</li>
<li>Some filthy shell command running</li>
</ul>
<p>A lot of not-using-Python comes down to friction, so make your own skeleton script with your favourite tidbits, then add the equivalent to your <code>.zshrc</code> or whatever:</p>
<pre><code class="lang-shell">function py-script(){curl https://raw.githubusercontent.com/leontrolski/leontrolski.github.io/refs/heads/master/code/my-script > $1 && chmod +x ./$1;}
</code></pre>
<p>Then just</p>
<pre><code class="lang-shell">py-script foo
./foo <span class="hljs-comment">--help</span>
</code></pre>
<p>bang!</p>
<hr>
<p>The script - it's not the most performant (eg. it reads everything into memory everywhere), but it gets the job done.</p>
<pre><code class="lang-python"><span class="hljs-comment">#!/usr/bin/env -S uv run --script</span>
<span class="hljs-comment"># /// script</span>
<span class="hljs-comment"># requires-python = "==3.13"</span>
<span class="hljs-comment"># dependencies = [</span>
<span class="hljs-comment"># "typer==0.16.0",</span>
<span class="hljs-comment"># ]</span>
<span class="hljs-comment"># ///</span>
<span class="hljs-keyword">from</span> pathlib <span class="hljs-keyword">import</span> Path
<span class="hljs-keyword">import</span> re
<span class="hljs-keyword">from</span> subprocess <span class="hljs-keyword">import</span> check_output
<span class="hljs-keyword">import</span> typer
app = typer.Typer()
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">sh</span><span class="hljs-params">(cmd: str)</span> -> str:</span>
<span class="hljs-keyword">return</span> check_output(cmd, shell=<span class="hljs-keyword">True</span>).decode()
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span><span class="hljs-params">(counts: list[int], *, name: str = <span class="hljs-string">"Oli"</span>)</span>:</span>
<span class="hljs-keyword">for</span> txt <span class="hljs-keyword">in</span> Path().glob(<span class="hljs-string">"*.txt"</span>):
<span class="hljs-keyword">for</span> line <span class="hljs-keyword">in</span> txt.read_text().splitlines():
<span class="hljs-keyword">if</span> match := re.search(<span class="hljs-string">r"==([\d.]+)"</span>, line):
print(match.groups()[<span class="hljs-number">0</span>])
commits = sh(<span class="hljs-string">'git log --pretty=format:"%H" | head -10'</span>).splitlines()
print(f<span class="hljs-string">"Hello {name} {counts=} {' '.join(commits)}"</span>)
typer.run(main)
</code></pre>
</body>
</html>