<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Hacker News: rgrau</title><link>https://news.ycombinator.com/user?id=rgrau</link><description>Hacker News RSS</description><docs>https://hnrss.org/</docs><generator>hnrss v2.1.1</generator><lastBuildDate>Tue, 28 Jul 2026 06:54:04 +0000</lastBuildDate><atom:link href="https://hnrss.org/user?id=rgrau" rel="self" type="application/rss+xml"></atom:link><item><title><![CDATA[New comment by rgrau in "A shell colon does nothing. Use it anyway"]]></title><description><![CDATA[
<p>So true. I think most of us who learned "advanced" bash is after being tired of feeling like an idiot looking at long bash scripts.<p>Usually, those scripts are written by people who didn't learn the "weird tricks", and use global variables (they didn't learn that `local` creates local variables), for example.<p>In bash, many times the "dumb way" takes 10 times more lines, and it's probably buggier than the "smart tricky way". So, in the end it's your choice what side you pick, and when to stop. Or, use a "real programming language" (I hate when people say this LOL)<p>After a while, you get a bit of stockholm syndrome, and you're just fine with bash as an orchestration language, and lean into unix principles. I accept its limitations, and I think it keeps me on my toes as it repels bloat.<p>idk if you were expecting an answer, but bash lives in this liminal space in the tower of languages that is worth a thought.</p>
]]></description><pubDate>Sun, 26 Jul 2026 18:51:52 +0000</pubDate><link>https://news.ycombinator.com/item?id=49061145</link><dc:creator>rgrau</dc:creator><comments>https://news.ycombinator.com/item?id=49061145</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=49061145</guid></item><item><title><![CDATA[New comment by rgrau in "A shell colon does nothing. Use it anyway"]]></title><description><![CDATA[
<p>Nice one! I love those weird bash tricks.<p>Some of the examples here are interesting, but they show parameter substitution more than colon itself: <a href="https://tldp.org/LDP/abs/html/parameter-substitution.html" rel="nofollow">https://tldp.org/LDP/abs/html/parameter-substitution.html</a><p>In small scopes, I tend to inline the `:?` validation inside the arg of the command. `echo "${1:? first param required}"`<p>Another usecase is to use colon in the  body of a while loop, while doing work in the condition of the loop.<p><pre><code>    while rlwrap -o -S'>> ' tr a-z A-Z ; do :; done
</code></pre>
Gives you the "do X while it succeeds. stop when it returns non-0" semantics.<p>I've also written about this and other bash tricks over the years in <a href="https://github.com/kidd/scripting-field-guide/blob/master/book.org#do-work-on-loop-conditions" rel="nofollow">https://github.com/kidd/scripting-field-guide/blob/master/bo...</a>. You might like them :)</p>
]]></description><pubDate>Sun, 26 Jul 2026 09:51:01 +0000</pubDate><link>https://news.ycombinator.com/item?id=49056388</link><dc:creator>rgrau</dc:creator><comments>https://news.ycombinator.com/item?id=49056388</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=49056388</guid></item><item><title><![CDATA[New comment by rgrau in "Shell Tricks That Make Life Easier (and Save Your Sanity)"]]></title><description><![CDATA[
<p>aha! I see what you mean, it's indeed a nice option, yep.<p>Using brackets like this is something I never thought of, and it's probably why it's hard for me to process it, but I can see it provides nice annotation capabilities, and it's a more self-contained style.<p>Thx for sharing!</p>
]]></description><pubDate>Thu, 26 Mar 2026 19:36:34 +0000</pubDate><link>https://news.ycombinator.com/item?id=47534690</link><dc:creator>rgrau</dc:creator><comments>https://news.ycombinator.com/item?id=47534690</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47534690</guid></item><item><title><![CDATA[New comment by rgrau in "Shell Tricks That Make Life Easier (and Save Your Sanity)"]]></title><description><![CDATA[
<p>That's very cool!<p>To take advantage of the "leading space" one, I have this, to mark some commands that I never want to record:<p><pre><code>       unhist () {
         alias $1=" $1"
       }
       unhist unhist
       unhist fzf
       unhist rghist     #custom command that greps .zhistory,...</code></pre></p>
]]></description><pubDate>Thu, 26 Mar 2026 17:33:55 +0000</pubDate><link>https://news.ycombinator.com/item?id=47533334</link><dc:creator>rgrau</dc:creator><comments>https://news.ycombinator.com/item?id=47533334</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47533334</guid></item><item><title><![CDATA[New comment by rgrau in "Shell Tricks That Make Life Easier (and Save Your Sanity)"]]></title><description><![CDATA[
<p>for multiline pipes, it's WAY better to format like<p><pre><code>    foo   |
      bar |
      baz 
</code></pre>
You don't have to use backquotes, AND, it allows you to comment line by line, because there's no backslash messing with the parser.<p>I also use a last `|\ncat` so you can delete any line and you don't have to worry about the last line being a bit different than the rest<p>I created a list of similar tricks in <a href="https://github.com/kidd/scripting-field-guide" rel="nofollow">https://github.com/kidd/scripting-field-guide</a> in case anyone wants to take a look</p>
]]></description><pubDate>Thu, 26 Mar 2026 17:28:17 +0000</pubDate><link>https://news.ycombinator.com/item?id=47533257</link><dc:creator>rgrau</dc:creator><comments>https://news.ycombinator.com/item?id=47533257</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47533257</guid></item><item><title><![CDATA[New comment by rgrau in "Shell Tricks That Make Life Easier (and Save Your Sanity)"]]></title><description><![CDATA[
<p>A similar trick:<p><pre><code>    #!/bin/sh
    $*
</code></pre>
that's my `~/bin/noglob` file, so when I call a zsh script from bash that uses `noglob`, it doesn't blow up.</p>
]]></description><pubDate>Thu, 26 Mar 2026 10:08:42 +0000</pubDate><link>https://news.ycombinator.com/item?id=47528565</link><dc:creator>rgrau</dc:creator><comments>https://news.ycombinator.com/item?id=47528565</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=47528565</guid></item><item><title><![CDATA[New comment by rgrau in "Show HN: Unregistry – “docker push” directly to servers without a registry"]]></title><description><![CDATA[
<p>I use a variant with ssh and some compression:<p><pre><code>    docker save $image | bzip2 | ssh "$host" 'bunzip2 | docker load'</code></pre></p>
]]></description><pubDate>Thu, 19 Jun 2025 00:41:56 +0000</pubDate><link>https://news.ycombinator.com/item?id=44314454</link><dc:creator>rgrau</dc:creator><comments>https://news.ycombinator.com/item?id=44314454</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=44314454</guid></item><item><title><![CDATA[New comment by rgrau in "Being a bash developer in the 21st century (2021)"]]></title><description><![CDATA[
<p>You can also nest those, so this way you can get a value from an argument, or an env var, and if none is set, error.<p><pre><code>    echo "${1:-${env_var:?I need a value for that!}}"</code></pre></p>
]]></description><pubDate>Fri, 22 Sep 2023 10:22:24 +0000</pubDate><link>https://news.ycombinator.com/item?id=37610213</link><dc:creator>rgrau</dc:creator><comments>https://news.ycombinator.com/item?id=37610213</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=37610213</guid></item><item><title><![CDATA[New comment by rgrau in "My favorite prime number generator"]]></title><description><![CDATA[
<p>Here's a solution in k, that uses a similar array oriented  approach:<p><pre><code>    &2=+/~x!/:\:x:!100
</code></pre>
I wrote a little explanation of it, in case anyone is 
curious about how it works: <a href="https://github.com/kidd/arraylangs-index/blob/master/notebooks/kprimes.ipynb">https://github.com/kidd/arraylangs-index/blob/master/noteboo...</a></p>
]]></description><pubDate>Wed, 23 Aug 2023 19:24:33 +0000</pubDate><link>https://news.ycombinator.com/item?id=37240952</link><dc:creator>rgrau</dc:creator><comments>https://news.ycombinator.com/item?id=37240952</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=37240952</guid></item><item><title><![CDATA[New comment by rgrau in "“Exit traps” can make your Bash scripts more robust and reliable (2013)"]]></title><description><![CDATA[
<p>I couldn't find a way to have more than one callback per signal, and created a system to have an array of callbacks:<p><a href="https://github.com/kidd/scripting-field-guide/blob/master/book.org#array-of-callbacks-on_exit">https://github.com/kidd/scripting-field-guide/blob/master/bo...</a><p>A nice bonus is that it also keeps the return value of the last non-callback function, so your script behaves better when called from other scripts.</p>
]]></description><pubDate>Tue, 20 Jun 2023 22:33:21 +0000</pubDate><link>https://news.ycombinator.com/item?id=36411636</link><dc:creator>rgrau</dc:creator><comments>https://news.ycombinator.com/item?id=36411636</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=36411636</guid></item><item><title><![CDATA[New comment by rgrau in "Moving fast with the core Vim motions"]]></title><description><![CDATA[
<p>Yep, good point. They are useful when you want to change the whole text inside the delimiters (and IME, it's most of the times), but they do different things than cf( because they also change/delete text behind the cursor.<p>The % approach works only on one direction.</p>
]]></description><pubDate>Thu, 15 Jun 2023 10:29:21 +0000</pubDate><link>https://news.ycombinator.com/item?id=36338530</link><dc:creator>rgrau</dc:creator><comments>https://news.ycombinator.com/item?id=36338530</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=36338530</guid></item><item><title><![CDATA[New comment by rgrau in "Moving fast with the core Vim motions"]]></title><description><![CDATA[
<p>I have 2 use cases for cf), but I don't use it a lot in the end:<p>One is when inside a parenthesis, and wanting to really delete till the closing parenthesis. But that would leave an unbalanced open paren. So in this case, I use ct) most of the times.<p>The other is when the cursor is before the opening parenthesis, and I want to delete the whole block.  In that case, I found c% to be easier to me. The advantage being that it works with other delimiters ({[]}) handles nesting better, and it's multiline friendly.<p>If instead of c%, we speak about d%, another plus is that dot (.) will repeat the generic command, so<p><pre><code>    if (is_foo()) {

      return 1;
    }
</code></pre>
can be cleared with `d%.` from the beginning of the first line.</p>
]]></description><pubDate>Thu, 15 Jun 2023 07:58:19 +0000</pubDate><link>https://news.ycombinator.com/item?id=36337619</link><dc:creator>rgrau</dc:creator><comments>https://news.ycombinator.com/item?id=36337619</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=36337619</guid></item><item><title><![CDATA[New comment by rgrau in "Being a Good Unix Neighbour"]]></title><description><![CDATA[
<p>Another advantage of pipes at the end is that you can comment lines and the full pipeline still works.<p>Some time ago I wrote a bunch of tips to make more ergonomic bash scripts: <a href="https://raimonster.com/scripting-field-guide/index.html" rel="nofollow">https://raimonster.com/scripting-field-guide/index.html</a><p>Also, Perl's diamond operator does the DWIM thing with files/stdin, and it's used directly as a line iterator. It handles multiple files (or none) in a row, which is a nice plus :) <a href="https://perlmaven.com/the-diamond-operator" rel="nofollow">https://perlmaven.com/the-diamond-operator</a></p>
]]></description><pubDate>Tue, 30 May 2023 14:34:52 +0000</pubDate><link>https://news.ycombinator.com/item?id=36125345</link><dc:creator>rgrau</dc:creator><comments>https://news.ycombinator.com/item?id=36125345</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=36125345</guid></item><item><title><![CDATA[New comment by rgrau in "Why Perl?"]]></title><description><![CDATA[
<p>Here's where he explains how he did it: <a href="https://www.youtube.com/watch?v=ORjyXcLDd9M">https://www.youtube.com/watch?v=ORjyXcLDd9M</a></p>
]]></description><pubDate>Fri, 21 Apr 2023 09:51:12 +0000</pubDate><link>https://news.ycombinator.com/item?id=35651635</link><dc:creator>rgrau</dc:creator><comments>https://news.ycombinator.com/item?id=35651635</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=35651635</guid></item><item><title><![CDATA[New comment by rgrau in "Shell script best practices, from a decade of scripting things"]]></title><description><![CDATA[
<p>Oh, I hadn't noticed that links are not highlighted as such (unless already visited).<p>Fixed, thanks!</p>
]]></description><pubDate>Thu, 27 Oct 2022 09:46:28 +0000</pubDate><link>https://news.ycombinator.com/item?id=33355344</link><dc:creator>rgrau</dc:creator><comments>https://news.ycombinator.com/item?id=33355344</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=33355344</guid></item><item><title><![CDATA[New comment by rgrau in "Shell script best practices, from a decade of scripting things"]]></title><description><![CDATA[
<p>Fixed, thanks!</p>
]]></description><pubDate>Thu, 27 Oct 2022 09:32:58 +0000</pubDate><link>https://news.ycombinator.com/item?id=33355246</link><dc:creator>rgrau</dc:creator><comments>https://news.ycombinator.com/item?id=33355246</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=33355246</guid></item><item><title><![CDATA[New comment by rgrau in "Shell script best practices, from a decade of scripting things"]]></title><description><![CDATA[
<p>> If appropriate, change to the script’s directory close to the start of the script.<p>> And it’s usually always appropriate.<p>I wouldn't think so.  You don't know where your script will be called from, and many times the parameters to the script are file paths, which are relative to the caller's path. So you usually don't want to do it.<p>I collected many tips&tricks from my experience with shell scripts that you may also find useful: <a href="https://raimonster.com/scripting-field-guide/" rel="nofollow">https://raimonster.com/scripting-field-guide/</a></p>
]]></description><pubDate>Thu, 27 Oct 2022 08:23:07 +0000</pubDate><link>https://news.ycombinator.com/item?id=33354744</link><dc:creator>rgrau</dc:creator><comments>https://news.ycombinator.com/item?id=33354744</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=33354744</guid></item><item><title><![CDATA[New comment by rgrau in "An Introduction to JQ"]]></title><description><![CDATA[
<p>Oh!<p>I didn't know that one could build an arbitrary string like that inside a map.<p>Thanks a lot for that, I agree it looks better!</p>
]]></description><pubDate>Wed, 25 Aug 2021 16:04:30 +0000</pubDate><link>https://news.ycombinator.com/item?id=28303363</link><dc:creator>rgrau</dc:creator><comments>https://news.ycombinator.com/item?id=28303363</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=28303363</guid></item><item><title><![CDATA[New comment by rgrau in "An Introduction to JQ"]]></title><description><![CDATA[
<p>A very useful function in jq is "join", which I use a lot to cook the final shape of the data (many times used with fzf/dmenu)<p>Here's a simple way to list and browse github issues of a given user/repo:<p><pre><code>    #!/usr/bin/env sh

    browse_url() {
      firefox http://github.com/$1/issues/$2
    }

    issue=$(curl https://api.github.com/repos/$1/issues |
          jq -r 'map([(.number|tostring), .title] | join(" | ")) | join("\n")' |
          dmenu -i -l 10 |
          awk "{print \$1}")

    browse_url $1 $issue

</code></pre>
Although the `| join("\n")` part could be done in a more idomatic way with just `[]`, sometimes the manual way are still clearer to me:<p><pre><code>    map([(.number|tostring), .title] | join(" | "))[]</code></pre></p>
]]></description><pubDate>Wed, 25 Aug 2021 08:25:46 +0000</pubDate><link>https://news.ycombinator.com/item?id=28299196</link><dc:creator>rgrau</dc:creator><comments>https://news.ycombinator.com/item?id=28299196</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=28299196</guid></item><item><title><![CDATA[New comment by rgrau in "Whitespaces and Strings in Bash (2018)"]]></title><description><![CDATA[
<p>Even funnier when you realize bash and zsh do different things (by default) there.<p><pre><code>   foo="ls -las"
   $foo
   "$foo"
</code></pre>
for zsh to split words, `setopt SH_SPLIT_WORDS`.</p>
]]></description><pubDate>Fri, 30 Jul 2021 11:24:32 +0000</pubDate><link>https://news.ycombinator.com/item?id=28006777</link><dc:creator>rgrau</dc:creator><comments>https://news.ycombinator.com/item?id=28006777</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=28006777</guid></item></channel></rss>