TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Scripting with Go (2022)

150 pointsby gus_leonelalmost 2 years ago

25 comments

sgarlandalmost 2 years ago
Every time I see things like this, I feel like the person must be unaware of awk.<p><pre><code> # the original one-liner to get unique IP addresses cut -d&#x27; &#x27; -f 1 access.log | sort | uniq -c | sort -rn | head # turns into this with GNU awk gawk &#x27;{PROCINFO[&quot;sorted_in&quot;] = &quot;@val_num_desc&quot;; a[$1]++} END {c=0; for (i in a) if (c++ &lt; 10) print a[i], i}&#x27; access.log </code></pre> It&#x27;s also far, far faster on larger files (base-spec M1 Air):<p><pre><code> $ wc -lc fake_log.txt 1000000 218433264 fake_log.txt $ hyperfine &quot;gawk &#x27;{PROCINFO[\&quot;sorted_in\&quot;] = \&quot;@val_num_desc\&quot;; a[\$1]++} END {c=0; for (i in a) if (c++ &lt;10) print a[i], i}&#x27; fake_log.txt&quot; Benchmark 1: gawk &#x27;{PROCINFO[&quot;sorted_in&quot;] = &quot;@val_num_desc&quot;; a[$1]++} END {c=0; for (i in a) if (c++ &lt;10) print a[i], i}&#x27; fake_log.txt Time (mean ± σ): 1.250 s ± 0.003 s [User: 1.185 s, System: 0.061 s] Range (min … max): 1.246 s … 1.254 s 10 runs $ hyperfine &quot;cut -d&#x27; &#x27; -f1 fake_log.txt | sort | uniq -c | sort -rn | head&quot; Benchmark 1: cut -d&#x27; &#x27; -f1 fake_log.txt | sort | uniq -c | sort -rn | head Time (mean ± σ): 4.844 s ± 0.020 s [User: 5.367 s, System: 0.087 s] Range (min … max): 4.817 s … 4.873 s 10 runs </code></pre> Interestingly, GNU cut is significantly faster than BSD cut on the M1:<p><pre><code> $ hyperfine &quot;gcut -d&#x27; &#x27; -f1 fake_log.txt | sort | uniq -c | sort -rn | head&quot; Benchmark 1: gcut -d&#x27; &#x27; -f1 fake_log.txt | sort | uniq -c | sort -rn | head Time (mean ± σ): 3.622 s ± 0.004 s [User: 4.149 s, System: 0.078 s] Range (min … max): 3.616 s … 3.629 s 10 runs</code></pre>
评论 #37200587 未加载
评论 #37199927 未加载
评论 #37200198 未加载
评论 #37201789 未加载
评论 #37201656 未加载
评论 #37202719 未加载
评论 #37202133 未加载
jerfalmost 2 years ago
I don&#x27;t do a lot of shell scripting type things in Go because it&#x27;s not a great language for it, but when I do, I take another approach, which is just to panic. Generics offer a nice little<p><pre><code> func Must[T any](x T, err error) T { if err != nil { panic(err) } return x } </code></pre> which you can wrap around any standard &quot;x, err :=&quot; function to just make it panic, and even prior to generics you could wrap a &quot;PanicOnErr(justReturnsErr())&quot;.<p>In the event that you want to handle errors in some other manner, you trivially can, and you&#x27;re not limited to just the pipeline design patterns, which are cool in some ways, but limiting when that&#x27;s all you have. (It can also be tricky to ensure the pipeline is written in a way that doesn&#x27;t generate a ton of memory traffic with intermediate arrays; I haven&#x27;t checked to see what the library they show does.) Presumably if I&#x27;m writing this in Go I have some other reason for wanting to do that, like having some non-trivial concurrency desire (using concurrency to handle a newline-delimited JSON file was my major use case, doing non-trivial though not terribly extensive work on the JSON).<p>While this may make some people freak, IMHO the real point of &quot;errors as values&quot; is not to force you to handle the errors in some very particular manner, but to make you <i>think</i> about the errors more deeply than a conventional exceptions-based program typically does. As such, it is perfectly legal and moral to think about your error handling and decide that what you really want is the entire program to terminate on the first error. Obviously this is not the correct solution for my API server blasting out tens of thousands of highly heterogeneous calls per second, but for a shell script it is quite often the correct answer. As something I have thought about and chosen deliberately, it&#x27;s fine.
simonwalmost 2 years ago
If you&#x27;re not familiar with Go there is one detail missing from this post (though it&#x27;s in the script README) - what a complete program looks like. Here&#x27;s the example from <a href="https:&#x2F;&#x2F;github.com&#x2F;bitfield&#x2F;script#a-realistic-use-case">https:&#x2F;&#x2F;github.com&#x2F;bitfield&#x2F;script#a-realistic-use-case</a><p><pre><code> package main import ( &quot;github.com&#x2F;bitfield&#x2F;script&quot; ) func main() { script.Stdin().Column(1).Freq().First(10).Stdout() }</code></pre>
评论 #37199848 未加载
评论 #37199486 未加载
simonwalmost 2 years ago
Inspired by comments in this thread, I threw together a Bash script that lets you do this:<p><pre><code> cat file.txt | .&#x2F;goscript.sh -c &#x27;script.Stdin().Column(1).Freq().First(10).Stdout()&#x27; </code></pre> You can also use it as a shebang line to write self-contained scripts.<p>Details here: <a href="https:&#x2F;&#x2F;til.simonwillison.net&#x2F;bash&#x2F;go-script" rel="nofollow noreferrer">https:&#x2F;&#x2F;til.simonwillison.net&#x2F;bash&#x2F;go-script</a>
booleandilemmaalmost 2 years ago
I like Go, but its insistence on not permitting unused imports and unused variables make it unsuitable for scripting, imo.<p>For scripting I want something that I can be fast and messy in. Go is the opposite of that.<p>It&#x27;s ok, a language doesn&#x27;t have to be good at everything.
评论 #37200609 未加载
评论 #37205462 未加载
perfmodealmost 2 years ago
From Sanjay Ghemawat, 9 years ago<p><a href="https:&#x2F;&#x2F;github.com&#x2F;ghemawat&#x2F;stream">https:&#x2F;&#x2F;github.com&#x2F;ghemawat&#x2F;stream</a>
pdimitaralmost 2 years ago
Shell scripting is quite fine up until certain complexity (say 500-1000 lines), after which adding even a single small feature becomes a huge drag. We&#x27;re talking hours for something that would take me 10 minutes in Golang and 15 in Rust.<p>Many people love to smirk and say &quot;just learn bash properly, duh&quot; but that&#x27;s missing the point that we never do big projects in bash so our muscle memory of bash is always kind of shallow. And by &quot;we&quot; I mean &quot;a lot of programmers&quot;; I am not stupid, but I have to learn bash&#x27;s intricacies every time almost from scratch and that&#x27;s not productive. It&#x27;s very normal for things to slip up from your memory when you&#x27;re not using them regularly. To make this even more annoying, nobody will pay me to work exclusively with bash for 3 months until it gets etched deep into my memory. So there&#x27;s that too.<p>I view OP as a good reminder that maybe universal-ish tools to get most of what we need from shell scripting exist even today but we aren&#x27;t giving them enough attention and energy and we don&#x27;t make them mainstream. Though it doesn&#x27;t help that Golang doesn&#x27;t automatically fetch dependencies when you just do `go run random_script.go`: <a href="https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;issues&#x2F;36513">https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;issues&#x2F;36513</a><p>I am not fixating on Golang in particular. But IMO <i>next_bash_or_something</i> should be due Soon™. It&#x27;s not a huge problem to install a single program when provisioning a new VM or container either so I am not sure why are people so averse to it.<p>So yeah, nice article. I like the direction.<p>EDIT: I know about nushell, oilshell and fish but admittedly never gave them a chance.
Hendriktoalmost 2 years ago
This is satire, right? I think commenters are completely missing the point.<p><a href="https:&#x2F;&#x2F;en.m.wikipedia.org&#x2F;wiki&#x2F;A_Modest_Proposal" rel="nofollow noreferrer">https:&#x2F;&#x2F;en.m.wikipedia.org&#x2F;wiki&#x2F;A_Modest_Proposal</a>
评论 #37202831 未加载
wudangmonkalmost 2 years ago
The unix philosophy of having small programs that take in input, process it and return a result has proven to a success, I just never understood why the next logical step of having this program in library form never became a thing. I guess shells are a bit useful but not as useful as a decent repl (common-lisp or the jupyter repl) where these programs can be used as if they were a function.
nerdbaggyalmost 2 years ago
I ended up using this for my cli scripting needs. <a href="https:&#x2F;&#x2F;github.com&#x2F;google&#x2F;zx">https:&#x2F;&#x2F;github.com&#x2F;google&#x2F;zx</a>
评论 #37210761 未加载
js2almost 2 years ago
Previous discussion (March 11, 2022 | 243 points | 66 comments):<p><a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=30641883">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=30641883</a>
geenatalmost 2 years ago
Would love to use more golang- amazing build system and cross compiler built in. &quot;All in one&quot; binaries are the best thing ever. I adore most of the ideas in the language.<p>.... but there are just soooo many little annoyances &#x2F; inconveniences which turn me off.<p>- No Optional Parameters. No Named Parameters. Throw us a bone Rob Pike, it&#x27;s 2023. Type inferred composite literals may be an OK compromise.. if we ever see them: <a href="https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;issues&#x2F;12854">https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;issues&#x2F;12854</a><p>- Unused import = will not compile. Unused variable = Will not compile. Give us the ability to turn off the warning.<p>- No null safe or nullish coalescing operator. (? in rust, ?? in php, etc.)<p>- Verbosity of if err != nil { return err; }<p>- A ternary operator would be nice, and could bring if err != nil to 1 line.<p>- No double declarations. “no new variables on left side of :=” .. For some odd reason “err” is OK here... Would be highly convenient for pipelines, so each result doesn&#x27;t need to be uniquely named.<p>I&#x27;d describe Go as a &quot;simple&quot; language- Not an &quot;easy&quot; language. 1-2 lines in Python is going to be 5-10 lines in golang.<p>Note: Nim has most of these..
评论 #37200802 未加载
评论 #37201710 未加载
评论 #37201100 未加载
评论 #37200685 未加载
ilytalmost 2 years ago
Perl was <i>literally</i> made for that, just use it
评论 #37210768 未加载
评论 #37204443 未加载
1vuio0pswjnm7almost 2 years ago
<p><pre><code> export LC_ALL=C awk &#x27;!a[$1]++&#x27; access.log|head </code></pre> If access.log is large enough, awk will fail.<p>When this happens, one can split access.log into pieces, process separately then recombine.<p>But that&#x27;s more or less what sort(1) does with large files, creating temporary files in $TMPDIR or other user-specified directory after -T if using GNU sort.<p>There was a way to eliminate duplicate lines from an unordered list using k&#x2F;q, without using temporary files but I stopped using it after Kx, Inc. was sold off and I started using musl exclusively. q requires glibc.<p>For example, something like<p><pre><code> #!&#x2F;bin&#x2F;sh # usage: $0 file echo &quot;k).Q.fs[l:0::\`:$1];l:?:l;\`:$1 0:l&quot;|exec q &gt;null; </code></pre> Can this be done in ngn k.<p>The other approach I use to avoid temporary files is to just put the list in an SQL database, add a UNIQUE constraint, and update the database.
评论 #37203987 未加载
fsmvalmost 2 years ago
I put together a go &quot;sh-bang&quot; line so you can just chmod +x your .go file and run it (and it works with go fmt unlike other options).<p><pre><code> &#x2F;*usr&#x2F;bin&#x2F;env go run &quot;$0&quot; &quot;$@&quot;; exit $? #*&#x2F; </code></pre> It&#x27;s fun try it out! Just make this the first line of the file.
DanielHBalmost 2 years ago
I have been thinking that JS template literals could be a great replacement for shell programming, allowing you to make more powerful syntax to emulate a lot of bash useful things while still having a lot of a proper programming language power<p>for example:<p><pre><code> import { jsh, cat, grep, PipeOutput } from &#x27;jsh; &#x2F;&#x2F; type PipeOutput = { stdout: ReadableStream, toString: () =&gt; Promise&lt;string&gt;, extra: Record&lt;string,any&gt; } function countLines(input: PipeOutput, argv: string[]): PipeOutput { &#x2F;&#x2F; ... } const textToLookFor = process.argv[1] const output: PipeOutput = jsh`${cat} file.txt | ${grep} ${textToLookFor} | ${countLines}` console.log(output.toString())</code></pre>
tambourine_manalmost 2 years ago
The pipe like code with dot notation reminds me a lot of jQuery. That’s a compliment.
评论 #37200822 未加载
评论 #37201713 未加载
评论 #37200333 未加载
nullwarpalmost 2 years ago
Oh very neat, thanks for posting I will definitely give this a try.
ComputerGurualmost 2 years ago
Tangentially related: I posted a shebang for scripting in rust some years ago, if anyone is interested: <a href="https:&#x2F;&#x2F;neosmart.net&#x2F;blog&#x2F;self-compiling-rust-code&#x2F;" rel="nofollow noreferrer">https:&#x2F;&#x2F;neosmart.net&#x2F;blog&#x2F;self-compiling-rust-code&#x2F;</a>
earthboundkidalmost 2 years ago
This post is several years old fwiw.
评论 #37199951 未加载
kardianosalmost 2 years ago
Interesting. I do something similar with my task <a href="https:&#x2F;&#x2F;github.com&#x2F;kardianos&#x2F;task">https:&#x2F;&#x2F;github.com&#x2F;kardianos&#x2F;task</a> package, which is in tern loosely based off of another package from 10-15 years ago.
评论 #37199975 未加载
fuzztesteralmost 2 years ago
Related: Ousterhout&#x27;s dichotomy:<p><a href="https:&#x2F;&#x2F;en.m.wikipedia.org&#x2F;wiki&#x2F;Ousterhout%27s_dichotomy" rel="nofollow noreferrer">https:&#x2F;&#x2F;en.m.wikipedia.org&#x2F;wiki&#x2F;Ousterhout%27s_dichotomy</a>
38almost 2 years ago
&gt; cut -d&#x27; &#x27; -f 1 access.log |sort |uniq -c |sort -rn |head<p>FYI Go has Compact now:<p><a href="https:&#x2F;&#x2F;godocs.io&#x2F;slices#Compact" rel="nofollow noreferrer">https:&#x2F;&#x2F;godocs.io&#x2F;slices#Compact</a>
dangalmost 2 years ago
Discussed at the time:<p><i>Scripting with Go</i> - <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=30641883">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=30641883</a> - March 2022 (66 comments)
nicechiantialmost 2 years ago
terrible idea