Lacking Natural Simplicity (Posts about bash)https://tkurtbond.github.io/categories/bash.atom2024-01-23T18:49:40ZT. Kurt BondNikolaSorting words separated by commashttps://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/2021-07-16T13:05:09-04:002021-07-16T13:05:09-04:00T. Kurt Bond<p>I often have lists of "words", separated by commas, possibly on
multiple lines, like this example from a <span class="file">Makefile</span>:</p>
<div class="code"><pre class="code makefile"><a id="rest_code_3f9e2296bd38445ca18cee60d98905a2-1" name="rest_code_3f9e2296bd38445ca18cee60d98905a2-1" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3f9e2296bd38445ca18cee60d98905a2-1"></a><span class="c"># bookman, schoolbook, palatino, times,</span>
<a id="rest_code_3f9e2296bd38445ca18cee60d98905a2-2" name="rest_code_3f9e2296bd38445ca18cee60d98905a2-2" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3f9e2296bd38445ca18cee60d98905a2-2"></a><span class="c"># helvetica, helvetica-narrow, optima, cormorant-garamond,</span>
<a id="rest_code_3f9e2296bd38445ca18cee60d98905a2-3" name="rest_code_3f9e2296bd38445ca18cee60d98905a2-3" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3f9e2296bd38445ca18cee60d98905a2-3"></a><span class="c"># or ebgaramond.</span>
</pre></div>
<p>I find these lists are always getting out of order, or they end up
with some short lines and some long lines. I want to be able to
reformat them automatically, like this:</p>
<div class="code"><pre class="code makefile"><a id="rest_code_60fb28c22cff4c09b245d4959c6fefbe-1" name="rest_code_60fb28c22cff4c09b245d4959c6fefbe-1" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_60fb28c22cff4c09b245d4959c6fefbe-1"></a><span class="c"># bookman, cormorant-garamond, ebgaramond, helvetica, helvetica-narrow,</span>
<a id="rest_code_60fb28c22cff4c09b245d4959c6fefbe-2" name="rest_code_60fb28c22cff4c09b245d4959c6fefbe-2" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_60fb28c22cff4c09b245d4959c6fefbe-2"></a><span class="c"># optima, palatino, schoolbook, or times.</span>
</pre></div>
<p>So, I wrote three scripts to deal with them,
<span class="command">sort-with-commas</span>, <span class="command">strip-leading-hash</span> to get rid
of the leading hashes and spaces, and <span class="command">prefix</span> to put the
leading hashes and spaces back.</p>
<p>Now, above I said "words", because really it's anything separated by
commas, so the "words" can contain space, etc.</p>
<p>Also, notice that the period after "ebgaramond" and the "or" before
"ebgaramond"` in the original list disappear, and an "or " appears
before the new end of the list, "times", and a period follows it. And
you can have have the same situation with "and". So, the <code class="docutils literal"><span class="pre">-p</span></code>
option to <span class="command">sort-with-commas</span> adds a period after the last
word, the <code class="docutils literal"><span class="pre">-a</span></code> option adds and "and " before the last word, and the
<code class="docutils literal"><span class="pre">-o</span></code> option adds an "or " before the last word. If you are sorting
only part of a list, you want to have a comma after the last "word",
so there is the option <code class="docutils literal"><span class="pre">-f</span></code> for that. And to remove the the period
from the original list, so it doesn't end up in the middle of the new
list, or to remove "and " or "or ", there is the <code class="docutils literal"><span class="pre">-r</span></code> option.</p>
<p>The default is to return the sorted list as one long line, but you can
easily reformat it to multiple lines by running it through the Unix
command <span class="command">fmt</span>.</p>
<p>Although in this case the list is prefixed with a "#" and some spaces
because it comes from a comment in a Makefile, you have to remove
those to sort the list. I wrote the script
<span class="command">strip-leading-hash</span> to do that, too, rather than having to
remember the <span class="command">sed</span> command to so that all the time.</p>
<p>So, to sort the original list I'd run the command</p>
<div class="code"><pre class="code bash"><a id="rest_code_b3f820ec80d945caa5ba409226e837bd-1" name="rest_code_b3f820ec80d945caa5ba409226e837bd-1" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_b3f820ec80d945caa5ba409226e837bd-1"></a>strip-leading-hash<span class="w"> </span><span class="p">|</span><span class="w"> </span>sort-with-commas<span class="w"> </span>-r<span class="w"> </span>-p<span class="w"> </span>-o<span class="w"> </span><span class="p">|</span><span class="w"> </span>fmt<span class="w"> </span><span class="p">|</span><span class="w"> </span>prefix<span class="w"> </span><span class="s2">"# "</span>
</pre></div>
<p>which means “strip the leading hashes and spaces, remove the trailing
period and the "and " or "or ", add a final period after the last word,
add an "or " before the final word, reformat as a paragraph, and
prefix the lines with the hash and spaces.”</p>
<p>When I use this I'm usually in <span class="app">emacs</span> and using <span class="key">M-|</span> to
run it on the region (the currently selected text), often with the
<span class="key">C-u</span> to replace the region with results.</p>
<p>Here's the main script, <span class="file">sort-with-commas</span>:</p>
<p><a class="reference external" href="https://tkurtbond.github.io/listings/sort-with-commas.html">sort-with-commas</a> <a class="reference external" href="https://tkurtbond.github.io/listings/sort-with-commas">(Source)</a></p>
<div class="code"><pre class="code bash"><a id="rest_code_3e180bb38dbc496e97037fca2aed9440-1" name="rest_code_3e180bb38dbc496e97037fca2aed9440-1" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-1"></a><span class="ch">#! /usr/bin/env bash</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-2" name="rest_code_3e180bb38dbc496e97037fca2aed9440-2" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-2"></a><span class="c1">###############################################################################</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-3" name="rest_code_3e180bb38dbc496e97037fca2aed9440-3" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-3"></a><span class="c1"># Sort a list of words that are seperated by commas, optionally followed by</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-4" name="rest_code_3e180bb38dbc496e97037fca2aed9440-4" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-4"></a><span class="c1"># a newline into a single line seperated by commas followed by spaces.</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-5" name="rest_code_3e180bb38dbc496e97037fca2aed9440-5" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-5"></a><span class="c1">#</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-6" name="rest_code_3e180bb38dbc496e97037fca2aed9440-6" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-6"></a><span class="c1"># For example: it translates (ignore the "# +" at the beginning of lines)</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-7" name="rest_code_3e180bb38dbc496e97037fca2aed9440-7" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-7"></a><span class="c1"># bookman, schoolbook,palatino,</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-8" name="rest_code_3e180bb38dbc496e97037fca2aed9440-8" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-8"></a><span class="c1"># times, helvetica, helvetica-narrow,</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-9" name="rest_code_3e180bb38dbc496e97037fca2aed9440-9" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-9"></a><span class="c1"># to</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-10" name="rest_code_3e180bb38dbc496e97037fca2aed9440-10" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-10"></a><span class="c1"># bookman, helvetica, helvetica-narrow, palatino, schoolbook, times</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-11" name="rest_code_3e180bb38dbc496e97037fca2aed9440-11" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-11"></a><span class="c1">###############################################################################</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-12" name="rest_code_3e180bb38dbc496e97037fca2aed9440-12" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-12"></a>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-13" name="rest_code_3e180bb38dbc496e97037fca2aed9440-13" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-13"></a><span class="nv">AND_OPT</span><span class="o">=</span>off<span class="w"> </span><span class="c1"># Insert "and " before last word.</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-14" name="rest_code_3e180bb38dbc496e97037fca2aed9440-14" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-14"></a><span class="nv">FINAL_OPT</span><span class="o">=</span>off<span class="w"> </span><span class="c1"># Leave "," after last word.</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-15" name="rest_code_3e180bb38dbc496e97037fca2aed9440-15" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-15"></a><span class="nv">OR_OPT</span><span class="o">=</span>off<span class="w"> </span><span class="c1"># Insert "or " before last word.</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-16" name="rest_code_3e180bb38dbc496e97037fca2aed9440-16" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-16"></a><span class="nv">PERIOD_OPT</span><span class="o">=</span>off<span class="w"> </span><span class="c1"># Insert a final period after last word.</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-17" name="rest_code_3e180bb38dbc496e97037fca2aed9440-17" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-17"></a><span class="nv">REMOVE_AND_OR_PERIOD_OPT</span><span class="o">=</span>off
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-18" name="rest_code_3e180bb38dbc496e97037fca2aed9440-18" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-18"></a>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-19" name="rest_code_3e180bb38dbc496e97037fca2aed9440-19" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-19"></a>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-20" name="rest_code_3e180bb38dbc496e97037fca2aed9440-20" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-20"></a><span class="nb">let</span><span class="w"> </span><span class="nv">errors</span><span class="o">=</span><span class="m">0</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-21" name="rest_code_3e180bb38dbc496e97037fca2aed9440-21" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-21"></a><span class="k">while</span><span class="w"> </span><span class="nb">getopts</span><span class="w"> </span><span class="s2">"?afhopr"</span><span class="w"> </span>opt
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-22" name="rest_code_3e180bb38dbc496e97037fca2aed9440-22" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-22"></a><span class="k">do</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-23" name="rest_code_3e180bb38dbc496e97037fca2aed9440-23" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-23"></a><span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="s2">"</span><span class="nv">$opt</span><span class="s2">"</span><span class="w"> </span><span class="k">in</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-24" name="rest_code_3e180bb38dbc496e97037fca2aed9440-24" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-24"></a><span class="w"> </span><span class="o">(</span><span class="se">\?</span><span class="p">|</span>h<span class="o">)</span><span class="w"> </span><span class="nb">let</span><span class="w"> </span>errors++<span class="w"> </span><span class="p">;;</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-25" name="rest_code_3e180bb38dbc496e97037fca2aed9440-25" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-25"></a><span class="w"> </span><span class="o">(</span>a<span class="o">)</span><span class="w"> </span><span class="nv">AND_OPT</span><span class="o">=</span>on<span class="w"> </span><span class="p">;;</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-26" name="rest_code_3e180bb38dbc496e97037fca2aed9440-26" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-26"></a><span class="w"> </span><span class="o">(</span>f<span class="o">)</span><span class="w"> </span><span class="nv">FINAL_OPT</span><span class="o">=</span>on<span class="w"> </span><span class="p">;;</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-27" name="rest_code_3e180bb38dbc496e97037fca2aed9440-27" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-27"></a><span class="w"> </span><span class="o">(</span>o<span class="o">)</span><span class="w"> </span><span class="nv">OR_OPT</span><span class="o">=</span>on<span class="w"> </span><span class="p">;;</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-28" name="rest_code_3e180bb38dbc496e97037fca2aed9440-28" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-28"></a><span class="w"> </span><span class="o">(</span>p<span class="o">)</span><span class="w"> </span><span class="nv">PERIOD_OPT</span><span class="o">=</span>on<span class="w"> </span><span class="p">;;</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-29" name="rest_code_3e180bb38dbc496e97037fca2aed9440-29" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-29"></a><span class="w"> </span><span class="o">(</span>r<span class="o">)</span><span class="w"> </span><span class="nv">REMOVE_AND_OR_PERIOD_OPT</span><span class="o">=</span>on<span class="w"> </span><span class="p">;;</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-30" name="rest_code_3e180bb38dbc496e97037fca2aed9440-30" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-30"></a><span class="w"> </span><span class="k">esac</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-31" name="rest_code_3e180bb38dbc496e97037fca2aed9440-31" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-31"></a><span class="k">done</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-32" name="rest_code_3e180bb38dbc496e97037fca2aed9440-32" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-32"></a>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-33" name="rest_code_3e180bb38dbc496e97037fca2aed9440-33" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-33"></a><span class="nb">shift</span><span class="w"> </span><span class="k">$((</span><span class="nv">OPTIND</span><span class="o">-</span><span class="m">1</span><span class="k">))</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-34" name="rest_code_3e180bb38dbc496e97037fca2aed9440-34" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-34"></a>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-35" name="rest_code_3e180bb38dbc496e97037fca2aed9440-35" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-35"></a><span class="o">[[</span><span class="w"> </span><span class="nv">$#</span><span class="w"> </span>><span class="w"> </span><span class="m">0</span><span class="w"> </span><span class="o">]]</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="o">[[</span><span class="w"> </span><span class="nv">$errors</span><span class="w"> </span>><span class="w"> </span><span class="m">0</span><span class="w"> </span><span class="o">]]</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="o">{</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-36" name="rest_code_3e180bb38dbc496e97037fca2aed9440-36" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-36"></a><span class="w"> </span>cat<span class="w"> </span><span class="s"><<EOF</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-37" name="rest_code_3e180bb38dbc496e97037fca2aed9440-37" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-37"></a><span class="s">usage: sort-with-commas [OPTION]</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-38" name="rest_code_3e180bb38dbc496e97037fca2aed9440-38" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-38"></a>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-39" name="rest_code_3e180bb38dbc496e97037fca2aed9440-39" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-39"></a><span class="s">This reads its standard input and sorts a line or multiple lines with</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-40" name="rest_code_3e180bb38dbc496e97037fca2aed9440-40" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-40"></a><span class="s">"words" separated by commas, then reassembles the line, words</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-41" name="rest_code_3e180bb38dbc496e97037fca2aed9440-41" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-41"></a><span class="s">separated by a comma and s space, optionally leaving a final comma</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-42" name="rest_code_3e180bb38dbc496e97037fca2aed9440-42" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-42"></a><span class="s">after the last word, or a period, and optionally putting "and " or "or</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-43" name="rest_code_3e180bb38dbc496e97037fca2aed9440-43" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-43"></a><span class="s">" before the last word.</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-44" name="rest_code_3e180bb38dbc496e97037fca2aed9440-44" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-44"></a>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-45" name="rest_code_3e180bb38dbc496e97037fca2aed9440-45" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-45"></a><span class="s">Options</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-46" name="rest_code_3e180bb38dbc496e97037fca2aed9440-46" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-46"></a>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-47" name="rest_code_3e180bb38dbc496e97037fca2aed9440-47" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-47"></a><span class="s">-? -h This message.</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-48" name="rest_code_3e180bb38dbc496e97037fca2aed9440-48" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-48"></a><span class="s">-a Insert "and " before last word.</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-49" name="rest_code_3e180bb38dbc496e97037fca2aed9440-49" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-49"></a><span class="s">-f Leave final comma after last word.</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-50" name="rest_code_3e180bb38dbc496e97037fca2aed9440-50" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-50"></a><span class="s">-o Insert "or " before last word.</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-51" name="rest_code_3e180bb38dbc496e97037fca2aed9440-51" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-51"></a><span class="s">-p Insert a period after the last word.</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-52" name="rest_code_3e180bb38dbc496e97037fca2aed9440-52" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-52"></a><span class="s">-r Remove "and " or "or " that occur at the beginning of a "word" in the</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-53" name="rest_code_3e180bb38dbc496e97037fca2aed9440-53" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-53"></a><span class="s"> original list.</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-54" name="rest_code_3e180bb38dbc496e97037fca2aed9440-54" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-54"></a>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-55" name="rest_code_3e180bb38dbc496e97037fca2aed9440-55" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-55"></a><span class="s">Note that combining -a and -o, or -f and -p do what you say, but the results</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-56" name="rest_code_3e180bb38dbc496e97037fca2aed9440-56" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-56"></a><span class="s">are silly.</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-57" name="rest_code_3e180bb38dbc496e97037fca2aed9440-57" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-57"></a><span class="s">EOF</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-58" name="rest_code_3e180bb38dbc496e97037fca2aed9440-58" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-58"></a><span class="w"> </span><span class="nb">exit</span><span class="w"> </span><span class="m">1</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-59" name="rest_code_3e180bb38dbc496e97037fca2aed9440-59" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-59"></a><span class="o">}</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-60" name="rest_code_3e180bb38dbc496e97037fca2aed9440-60" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-60"></a>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-61" name="rest_code_3e180bb38dbc496e97037fca2aed9440-61" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-61"></a>tr<span class="w"> </span><span class="s1">','</span><span class="w"> </span><span class="s1">'\n'</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>sed<span class="w"> </span>-E<span class="w"> </span>-e<span class="w"> </span><span class="s1">'s/^[ \t]+//'</span><span class="w"> </span>-e<span class="w"> </span><span class="s1">'/^$/d'</span><span class="w"> </span><span class="p">|</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-62" name="rest_code_3e180bb38dbc496e97037fca2aed9440-62" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-62"></a><span class="w"> </span><span class="o">([[</span><span class="w"> </span><span class="s2">"</span><span class="nv">$REMOVE_AND_OR_PERIOD_OPT</span><span class="s2">"</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"on"</span><span class="w"> </span><span class="o">]]</span><span class="w"> </span><span class="o">&&</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-63" name="rest_code_3e180bb38dbc496e97037fca2aed9440-63" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-63"></a><span class="w"> </span>sed<span class="w"> </span>-E<span class="w"> </span>-e<span class="w"> </span><span class="s1">'s/^(and|or)[ \t]+//'</span><span class="w"> </span>-e<span class="w"> </span><span class="s1">'s/\.[ \t]*$//'</span><span class="w"> </span><span class="o">||</span><span class="w"> </span>cat<span class="o">)</span><span class="w"> </span><span class="p">|</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-64" name="rest_code_3e180bb38dbc496e97037fca2aed9440-64" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-64"></a><span class="w"> </span>sort<span class="w"> </span>-u<span class="w"> </span><span class="p">|</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-65" name="rest_code_3e180bb38dbc496e97037fca2aed9440-65" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-65"></a><span class="w"> </span>sed<span class="w"> </span>-E<span class="w"> </span>-e<span class="w"> </span><span class="s1">'s/$/,/'</span><span class="w"> </span><span class="p">|</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-66" name="rest_code_3e180bb38dbc496e97037fca2aed9440-66" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-66"></a><span class="w"> </span><span class="o">(</span><span class="k">if</span><span class="w"> </span><span class="o">[[</span><span class="w"> </span><span class="s2">"</span><span class="nv">$AND_OPT</span><span class="s2">"</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"on"</span><span class="w"> </span><span class="o">]]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span><span class="w"> </span>sed<span class="w"> </span>-e<span class="w"> </span><span class="s1">'$s/^/and /'</span><span class="p">;</span><span class="w"> </span><span class="k">else</span><span class="w"> </span>cat<span class="p">;</span><span class="w"> </span><span class="k">fi</span><span class="o">)</span><span class="w"> </span><span class="p">|</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-67" name="rest_code_3e180bb38dbc496e97037fca2aed9440-67" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-67"></a><span class="w"> </span><span class="o">(</span><span class="k">if</span><span class="w"> </span><span class="o">[[</span><span class="w"> </span><span class="s2">"</span><span class="nv">$FINAL_OPT</span><span class="s2">"</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"on"</span><span class="w"> </span><span class="o">]]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span><span class="w"> </span>cat<span class="p">;</span><span class="w"> </span><span class="k">else</span><span class="w"> </span>sed<span class="w"> </span>-e<span class="w"> </span><span class="s1">'$s/,//'</span><span class="p">;</span><span class="w"> </span><span class="k">fi</span><span class="o">)</span><span class="w"> </span><span class="p">|</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-68" name="rest_code_3e180bb38dbc496e97037fca2aed9440-68" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-68"></a><span class="w"> </span><span class="o">(</span><span class="k">if</span><span class="w"> </span><span class="o">[[</span><span class="w"> </span><span class="s2">"</span><span class="nv">$OR_OPT</span><span class="s2">"</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"on"</span><span class="w"> </span><span class="o">]]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span><span class="w"> </span>sed<span class="w"> </span>-e<span class="w"> </span><span class="s1">'$s/^/or /'</span><span class="p">;</span><span class="w"> </span><span class="k">else</span><span class="w"> </span>cat<span class="p">;</span><span class="w"> </span><span class="k">fi</span><span class="o">)</span><span class="w"> </span><span class="p">|</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-69" name="rest_code_3e180bb38dbc496e97037fca2aed9440-69" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-69"></a><span class="w"> </span><span class="o">(</span><span class="k">if</span><span class="w"> </span><span class="o">[[</span><span class="w"> </span><span class="s2">"</span><span class="nv">$PERIOD_OPT</span><span class="s2">"</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"on"</span><span class="w"> </span><span class="o">]]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span><span class="w"> </span>sed<span class="w"> </span>-e<span class="w"> </span><span class="s1">'$s/$/./'</span><span class="p">;</span><span class="w"> </span><span class="k">else</span><span class="w"> </span>cat<span class="p">;</span><span class="w"> </span><span class="k">fi</span><span class="o">)</span><span class="w"> </span><span class="p">|</span>
<a id="rest_code_3e180bb38dbc496e97037fca2aed9440-70" name="rest_code_3e180bb38dbc496e97037fca2aed9440-70" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_3e180bb38dbc496e97037fca2aed9440-70"></a><span class="w"> </span>tr<span class="w"> </span><span class="s1">'\n'</span><span class="w"> </span><span class="s1">' '</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>sed<span class="w"> </span>-E<span class="w"> </span>-e<span class="w"> </span><span class="s1">'s/[ ]$//'</span>
</pre></div>
<p>Here's <span class="file">strip-leading-hash</span>:</p>
<p><a class="reference external" href="https://tkurtbond.github.io/listings/strip-leading-hash.html">strip-leading-hash</a> <a class="reference external" href="https://tkurtbond.github.io/listings/strip-leading-hash">(Source)</a></p>
<div class="code"><pre class="code bash"><a id="rest_code_84c1bc3f92c543fea38dda13fbcf8f3e-1" name="rest_code_84c1bc3f92c543fea38dda13fbcf8f3e-1" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_84c1bc3f92c543fea38dda13fbcf8f3e-1"></a><span class="ch">#! /usr/bin/env bash</span>
<a id="rest_code_84c1bc3f92c543fea38dda13fbcf8f3e-2" name="rest_code_84c1bc3f92c543fea38dda13fbcf8f3e-2" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_84c1bc3f92c543fea38dda13fbcf8f3e-2"></a>
<a id="rest_code_84c1bc3f92c543fea38dda13fbcf8f3e-3" name="rest_code_84c1bc3f92c543fea38dda13fbcf8f3e-3" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_84c1bc3f92c543fea38dda13fbcf8f3e-3"></a>sed<span class="w"> </span>-E<span class="w"> </span>-e<span class="w"> </span><span class="s1">'s/^#[ \t]*//'</span>
</pre></div>
<p>And here's <span class="file">prefix</span>:</p>
<p><a class="reference external" href="https://tkurtbond.github.io/listings/prefix.html">prefix</a> <a class="reference external" href="https://tkurtbond.github.io/listings/prefix">(Source)</a></p>
<div class="code"><pre class="code bash"><a id="rest_code_8a4e0ab08ed04bb5b0bff8f691b9140c-1" name="rest_code_8a4e0ab08ed04bb5b0bff8f691b9140c-1" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_8a4e0ab08ed04bb5b0bff8f691b9140c-1"></a><span class="ch">#! /usr/bin/env bash</span>
<a id="rest_code_8a4e0ab08ed04bb5b0bff8f691b9140c-2" name="rest_code_8a4e0ab08ed04bb5b0bff8f691b9140c-2" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_8a4e0ab08ed04bb5b0bff8f691b9140c-2"></a>
<a id="rest_code_8a4e0ab08ed04bb5b0bff8f691b9140c-3" name="rest_code_8a4e0ab08ed04bb5b0bff8f691b9140c-3" href="https://tkurtbond.github.io/posts/2021/07/16/sorting-words-separated-by-commas/#rest_code_8a4e0ab08ed04bb5b0bff8f691b9140c-3"></a>sed<span class="w"> </span><span class="s2">"s/^/</span><span class="nv">$1</span><span class="s2">/"</span>
</pre></div>Logging the output of long commands run multiple timeshttps://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/2021-07-07T12:47:25-04:002021-07-07T12:47:25-04:00T. Kurt Bond<p>I often run commands that produce a lot of output that needs to saved
for debugging, and often the commands have to be repeated multiple
times to get things to work. For example, building software from
source, often using the familiar <code class="docutils literal">./configure; make; make install</code>
paradigm.</p>
<p>So, the first thing is to try is to use the venerable <span class="command">tee</span> command.</p>
<div class="code"><pre class="code bash"><a id="rest_code_1e31e2b85af64908b9d390d9f64fdd7c-1" name="rest_code_1e31e2b85af64908b9d390d9f64fdd7c-1" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_1e31e2b85af64908b9d390d9f64fdd7c-1"></a>./configure<span class="w"> </span><span class="m">2</span>><span class="p">&</span><span class="m">1</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>tee<span class="w"> </span>Log.configure
<a id="rest_code_1e31e2b85af64908b9d390d9f64fdd7c-2" name="rest_code_1e31e2b85af64908b9d390d9f64fdd7c-2" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_1e31e2b85af64908b9d390d9f64fdd7c-2"></a>make<span class="w"> </span><span class="m">2</span>><span class="p">&</span><span class="m">1</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>tee<span class="w"> </span>Log.make
<a id="rest_code_1e31e2b85af64908b9d390d9f64fdd7c-3" name="rest_code_1e31e2b85af64908b9d390d9f64fdd7c-3" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_1e31e2b85af64908b9d390d9f64fdd7c-3"></a>make<span class="w"> </span>install<span class="w"> </span><span class="m">2</span>><span class="p">&</span><span class="m">1</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>tee<span class="w"> </span>Log.make-install
</pre></div>
<p>To make the log files easy to find I use a <span class="file">Log.</span> prefix.</p>
<p>But I often need to run the commands multiple times, and want to save
each run under a new filename, so if the filename already exists I
want to add a number to the end and then increment the number until I
find one that hasn't been used. And I'd like the filename to have the
date in YYYY-MM-DD format, so the resulting names look like
<span class="file">Log.make-install-2021-07-07_2</span>.</p>
<p>So I wrote a bash function <span class="command">incf</span> (increment filename) to put in
<span class="file">.bashrc</span> that generates such a name:</p>
<div class="code"><pre class="code bash"><a id="rest_code_9335958ced034ccabde8d1fc693cd728-1" name="rest_code_9335958ced034ccabde8d1fc693cd728-1" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-1"></a>incf<span class="w"> </span><span class="o">()</span><span class="w"> </span><span class="o">{</span>
<a id="rest_code_9335958ced034ccabde8d1fc693cd728-2" name="rest_code_9335958ced034ccabde8d1fc693cd728-2" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-2"></a><span class="w"> </span><span class="c1"># Construct a filename from PREFIX, "_YYYY-MM-DD", optionally _N (where N</span>
<a id="rest_code_9335958ced034ccabde8d1fc693cd728-3" name="rest_code_9335958ced034ccabde8d1fc693cd728-3" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-3"></a><span class="w"> </span><span class="c1"># is 1 or greater) if the filename already exists, and optionally SUFFIX.</span>
<a id="rest_code_9335958ced034ccabde8d1fc693cd728-4" name="rest_code_9335958ced034ccabde8d1fc693cd728-4" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-4"></a><span class="w"> </span><span class="c1"># Example: "incf file .tar.gz" results in "file_2021-07-07.tar.gz", or</span>
<a id="rest_code_9335958ced034ccabde8d1fc693cd728-5" name="rest_code_9335958ced034ccabde8d1fc693cd728-5" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-5"></a><span class="w"> </span><span class="c1"># "file_2021-07-07_N.tar.gz" if "file_2021-07-07.tar.gz" already exists,</span>
<a id="rest_code_9335958ced034ccabde8d1fc693cd728-6" name="rest_code_9335958ced034ccabde8d1fc693cd728-6" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-6"></a><span class="w"> </span><span class="c1"># where N is 1 or greater.</span>
<a id="rest_code_9335958ced034ccabde8d1fc693cd728-7" name="rest_code_9335958ced034ccabde8d1fc693cd728-7" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-7"></a><span class="w"> </span><span class="nb">local</span><span class="w"> </span>prefix<span class="w"> </span>suffix<span class="w"> </span>fileprefix<span class="w"> </span>i<span class="w"> </span>testname<span class="w"> </span>sep1<span class="w"> </span>sep2
<a id="rest_code_9335958ced034ccabde8d1fc693cd728-8" name="rest_code_9335958ced034ccabde8d1fc693cd728-8" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-8"></a><span class="w"> </span><span class="nv">prefix</span><span class="o">=</span><span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span>
<a id="rest_code_9335958ced034ccabde8d1fc693cd728-9" name="rest_code_9335958ced034ccabde8d1fc693cd728-9" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-9"></a><span class="w"> </span><span class="nv">suffix</span><span class="o">=</span><span class="s2">"</span><span class="nv">$2</span><span class="s2">"</span>
<a id="rest_code_9335958ced034ccabde8d1fc693cd728-10" name="rest_code_9335958ced034ccabde8d1fc693cd728-10" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-10"></a><span class="w"> </span><span class="nv">sep1</span><span class="o">=</span><span class="s2">"_"</span>
<a id="rest_code_9335958ced034ccabde8d1fc693cd728-11" name="rest_code_9335958ced034ccabde8d1fc693cd728-11" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-11"></a><span class="w"> </span><span class="nv">sep2</span><span class="o">=</span><span class="s2">"_"</span>
<a id="rest_code_9335958ced034ccabde8d1fc693cd728-12" name="rest_code_9335958ced034ccabde8d1fc693cd728-12" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-12"></a><span class="w"> </span><span class="nv">fileprefix</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">prefix</span><span class="si">}${</span><span class="nv">sep1</span><span class="si">}</span><span class="k">$(</span>date<span class="w"> </span>+%F<span class="k">)</span><span class="s2">"</span>
<a id="rest_code_9335958ced034ccabde8d1fc693cd728-13" name="rest_code_9335958ced034ccabde8d1fc693cd728-13" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-13"></a><span class="w"> </span><span class="nb">let</span><span class="w"> </span><span class="nv">i</span><span class="o">=</span><span class="m">0</span>
<a id="rest_code_9335958ced034ccabde8d1fc693cd728-14" name="rest_code_9335958ced034ccabde8d1fc693cd728-14" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-14"></a><span class="w"> </span><span class="c1"># The zeroth filename doesn't have the number.</span>
<a id="rest_code_9335958ced034ccabde8d1fc693cd728-15" name="rest_code_9335958ced034ccabde8d1fc693cd728-15" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-15"></a><span class="w"> </span><span class="nv">testname</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">fileprefix</span><span class="si">}${</span><span class="nv">suffix</span><span class="si">}</span><span class="s2">"</span>
<a id="rest_code_9335958ced034ccabde8d1fc693cd728-16" name="rest_code_9335958ced034ccabde8d1fc693cd728-16" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-16"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="nb">true</span>
<a id="rest_code_9335958ced034ccabde8d1fc693cd728-17" name="rest_code_9335958ced034ccabde8d1fc693cd728-17" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-17"></a><span class="w"> </span><span class="k">do</span>
<a id="rest_code_9335958ced034ccabde8d1fc693cd728-18" name="rest_code_9335958ced034ccabde8d1fc693cd728-18" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-18"></a><span class="w"> </span><span class="o">[</span><span class="w"> </span>!<span class="w"> </span>-e<span class="w"> </span><span class="s2">"</span><span class="nv">$testname</span><span class="s2">"</span><span class="w"> </span><span class="o">]</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="k">break</span>
<a id="rest_code_9335958ced034ccabde8d1fc693cd728-19" name="rest_code_9335958ced034ccabde8d1fc693cd728-19" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-19"></a><span class="w"> </span><span class="o">((</span>i++<span class="o">))</span>
<a id="rest_code_9335958ced034ccabde8d1fc693cd728-20" name="rest_code_9335958ced034ccabde8d1fc693cd728-20" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-20"></a><span class="w"> </span><span class="nv">testname</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">fileprefix</span><span class="si">}${</span><span class="nv">sep2</span><span class="si">}${</span><span class="nv">i</span><span class="si">}${</span><span class="nv">suffix</span><span class="si">}</span><span class="s2">"</span>
<a id="rest_code_9335958ced034ccabde8d1fc693cd728-21" name="rest_code_9335958ced034ccabde8d1fc693cd728-21" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-21"></a><span class="w"> </span><span class="k">done</span>
<a id="rest_code_9335958ced034ccabde8d1fc693cd728-22" name="rest_code_9335958ced034ccabde8d1fc693cd728-22" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-22"></a><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"</span><span class="nv">$testname</span><span class="s2">"</span>
<a id="rest_code_9335958ced034ccabde8d1fc693cd728-23" name="rest_code_9335958ced034ccabde8d1fc693cd728-23" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_9335958ced034ccabde8d1fc693cd728-23"></a><span class="o">}</span>
</pre></div>
<p>And then I wrote a bash function that uses <span class="command">incf</span> to generate
the <span class="file">Log.</span> filename, potentially in a different directory:</p>
<div class="code"><pre class="code bash"><a id="rest_code_4f4600014e61447fbba8e8f676adc0a2-1" name="rest_code_4f4600014e61447fbba8e8f676adc0a2-1" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_4f4600014e61447fbba8e8f676adc0a2-1"></a>logf<span class="w"> </span><span class="o">()</span><span class="w"> </span><span class="o">{</span>
<a id="rest_code_4f4600014e61447fbba8e8f676adc0a2-2" name="rest_code_4f4600014e61447fbba8e8f676adc0a2-2" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_4f4600014e61447fbba8e8f676adc0a2-2"></a><span class="w"> </span><span class="c1"># Construct a filename, possibly in another directory, that starts with</span>
<a id="rest_code_4f4600014e61447fbba8e8f676adc0a2-3" name="rest_code_4f4600014e61447fbba8e8f676adc0a2-3" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_4f4600014e61447fbba8e8f676adc0a2-3"></a><span class="w"> </span><span class="c1"># "Log." and ends with "YYYY-MM-DD" and optionally "_N", where N is 1 or</span>
<a id="rest_code_4f4600014e61447fbba8e8f676adc0a2-4" name="rest_code_4f4600014e61447fbba8e8f676adc0a2-4" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_4f4600014e61447fbba8e8f676adc0a2-4"></a><span class="w"> </span><span class="c1"># greater, if the filename already exists.</span>
<a id="rest_code_4f4600014e61447fbba8e8f676adc0a2-5" name="rest_code_4f4600014e61447fbba8e8f676adc0a2-5" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_4f4600014e61447fbba8e8f676adc0a2-5"></a><span class="w"> </span><span class="nb">local</span><span class="w"> </span>dn<span class="w"> </span>bn<span class="w"> </span>fn
<a id="rest_code_4f4600014e61447fbba8e8f676adc0a2-6" name="rest_code_4f4600014e61447fbba8e8f676adc0a2-6" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_4f4600014e61447fbba8e8f676adc0a2-6"></a><span class="w"> </span><span class="nv">dn</span><span class="o">=</span><span class="s2">"</span><span class="k">$(</span>dirname<span class="w"> </span><span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span><span class="k">)</span><span class="s2">"</span>
<a id="rest_code_4f4600014e61447fbba8e8f676adc0a2-7" name="rest_code_4f4600014e61447fbba8e8f676adc0a2-7" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_4f4600014e61447fbba8e8f676adc0a2-7"></a><span class="w"> </span><span class="nv">bn</span><span class="o">=</span><span class="s2">"Log.</span><span class="k">$(</span>basename<span class="w"> </span><span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span><span class="k">)</span><span class="s2">"</span>
<a id="rest_code_4f4600014e61447fbba8e8f676adc0a2-8" name="rest_code_4f4600014e61447fbba8e8f676adc0a2-8" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_4f4600014e61447fbba8e8f676adc0a2-8"></a><span class="w"> </span><span class="nv">fn</span><span class="o">=</span><span class="s2">"</span><span class="k">$(</span>incf<span class="w"> </span><span class="s2">"</span><span class="nv">$dn</span><span class="s2">/</span><span class="nv">$bn</span><span class="s2">"</span><span class="k">)</span><span class="s2">"</span>
<a id="rest_code_4f4600014e61447fbba8e8f676adc0a2-9" name="rest_code_4f4600014e61447fbba8e8f676adc0a2-9" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_4f4600014e61447fbba8e8f676adc0a2-9"></a><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="nv">$fn</span>
<a id="rest_code_4f4600014e61447fbba8e8f676adc0a2-10" name="rest_code_4f4600014e61447fbba8e8f676adc0a2-10" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_4f4600014e61447fbba8e8f676adc0a2-10"></a><span class="o">}</span>
</pre></div>
<p>And then I wrote a <span class="command">log</span> command that uses <span class="command">logf</span>
and tees its input into that file:</p>
<div class="code"><pre class="code bash"><a id="rest_code_ab8cbf1c22dd43dbb3fd84ce5797adb0-1" name="rest_code_ab8cbf1c22dd43dbb3fd84ce5797adb0-1" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_ab8cbf1c22dd43dbb3fd84ce5797adb0-1"></a>log<span class="w"> </span><span class="o">()</span><span class="w"> </span><span class="o">{</span>
<a id="rest_code_ab8cbf1c22dd43dbb3fd84ce5797adb0-2" name="rest_code_ab8cbf1c22dd43dbb3fd84ce5797adb0-2" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_ab8cbf1c22dd43dbb3fd84ce5797adb0-2"></a><span class="w"> </span><span class="c1"># tee the input into a log file.</span>
<a id="rest_code_ab8cbf1c22dd43dbb3fd84ce5797adb0-3" name="rest_code_ab8cbf1c22dd43dbb3fd84ce5797adb0-3" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_ab8cbf1c22dd43dbb3fd84ce5797adb0-3"></a><span class="w"> </span>tee<span class="w"> </span><span class="k">$(</span>logf<span class="w"> </span><span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span><span class="k">)</span>
<a id="rest_code_ab8cbf1c22dd43dbb3fd84ce5797adb0-4" name="rest_code_ab8cbf1c22dd43dbb3fd84ce5797adb0-4" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_ab8cbf1c22dd43dbb3fd84ce5797adb0-4"></a><span class="o">}</span>
</pre></div>
<p>So running <code class="docutils literal">./configure <span class="pre">2>&1</span> | log ~/tmp/configure</code> generates a file
<span class="file">Log.configure_2021-07-07</span> in the <span class="file">~/tmp</span> directory.</p>
<p>But what if I specify a lot of options to the command, and would like
record if it in the log file, so if I get interrupted and then come
back some time later I can use the same command?</p>
<p>First I wrote a base function, <span class="command">cleanname</span>, that takes a string and
converts it to something that should be safe to use as a filename.</p>
<div class="code"><pre class="code bash"><a id="rest_code_8039761b61ed4ac1bbf6929853e9d86d-1" name="rest_code_8039761b61ed4ac1bbf6929853e9d86d-1" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_8039761b61ed4ac1bbf6929853e9d86d-1"></a>cleanname<span class="w"> </span><span class="o">()</span><span class="w"> </span><span class="o">{</span>
<a id="rest_code_8039761b61ed4ac1bbf6929853e9d86d-2" name="rest_code_8039761b61ed4ac1bbf6929853e9d86d-2" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_8039761b61ed4ac1bbf6929853e9d86d-2"></a><span class="w"> </span><span class="c1"># Clean up a string so it is (relatively) safe to use as a filename.</span>
<a id="rest_code_8039761b61ed4ac1bbf6929853e9d86d-3" name="rest_code_8039761b61ed4ac1bbf6929853e9d86d-3" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_8039761b61ed4ac1bbf6929853e9d86d-3"></a><span class="w"> </span><span class="nb">local</span><span class="w"> </span><span class="nv">cmd</span><span class="o">=</span><span class="s2">"</span><span class="nv">$*</span><span class="s2">"</span><span class="w"> </span>name
<a id="rest_code_8039761b61ed4ac1bbf6929853e9d86d-4" name="rest_code_8039761b61ed4ac1bbf6929853e9d86d-4" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_8039761b61ed4ac1bbf6929853e9d86d-4"></a><span class="w"> </span><span class="nv">name</span><span class="o">=</span><span class="k">$(</span><span class="nb">echo</span><span class="w"> </span><span class="s2">"</span><span class="nv">$cmd</span><span class="s2">"</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>sed<span class="w"> </span><span class="s1">'s/[ =";?*&^%$#@!~`|()<>]/-/g'</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="se">\</span>
<a id="rest_code_8039761b61ed4ac1bbf6929853e9d86d-5" name="rest_code_8039761b61ed4ac1bbf6929853e9d86d-5" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_8039761b61ed4ac1bbf6929853e9d86d-5"></a><span class="w"> </span>sed<span class="w"> </span><span class="s2">"s#[/']#-#g"</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>sed<span class="w"> </span>-E<span class="w"> </span><span class="s1">'s/--+/-/g'</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="se">\</span>
<a id="rest_code_8039761b61ed4ac1bbf6929853e9d86d-6" name="rest_code_8039761b61ed4ac1bbf6929853e9d86d-6" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_8039761b61ed4ac1bbf6929853e9d86d-6"></a><span class="w"> </span>sed<span class="w"> </span>-E<span class="w"> </span><span class="s1">'s/(^[-.]+|-+$)//g'</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="se">\</span>
<a id="rest_code_8039761b61ed4ac1bbf6929853e9d86d-7" name="rest_code_8039761b61ed4ac1bbf6929853e9d86d-7" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_8039761b61ed4ac1bbf6929853e9d86d-7"></a><span class="w"> </span>sed<span class="w"> </span>-E<span class="w"> </span><span class="s1">'s/\.\.\.*/./g'</span><span class="k">)</span>
<a id="rest_code_8039761b61ed4ac1bbf6929853e9d86d-8" name="rest_code_8039761b61ed4ac1bbf6929853e9d86d-8" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_8039761b61ed4ac1bbf6929853e9d86d-8"></a><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"</span><span class="nv">$name</span><span class="s2">"</span>
<a id="rest_code_8039761b61ed4ac1bbf6929853e9d86d-9" name="rest_code_8039761b61ed4ac1bbf6929853e9d86d-9" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_8039761b61ed4ac1bbf6929853e9d86d-9"></a><span class="o">}</span>
</pre></div>
<p>Then I wrote a bash function, <span class="command">exlog</span>, to use the whole
command with its options as part of the filename (constructed with
<span class="command">cleanname</span>, and also include the whole command in the log output:</p>
<div class="code"><pre class="code bash"><a id="rest_code_eed27f36decf4f3fa2a8ede786d10a79-1" name="rest_code_eed27f36decf4f3fa2a8ede786d10a79-1" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_eed27f36decf4f3fa2a8ede786d10a79-1"></a>exlog<span class="w"> </span><span class="o">()</span><span class="w"> </span><span class="o">{</span>
<a id="rest_code_eed27f36decf4f3fa2a8ede786d10a79-2" name="rest_code_eed27f36decf4f3fa2a8ede786d10a79-2" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_eed27f36decf4f3fa2a8ede786d10a79-2"></a><span class="w"> </span><span class="c1"># Execute a shell command and log it to "Log.<cmd-as-safe-filename>"</span>
<a id="rest_code_eed27f36decf4f3fa2a8ede786d10a79-3" name="rest_code_eed27f36decf4f3fa2a8ede786d10a79-3" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_eed27f36decf4f3fa2a8ede786d10a79-3"></a><span class="w"> </span><span class="nb">local</span><span class="w"> </span><span class="nv">cmd</span><span class="o">=</span><span class="s2">"</span><span class="nv">$*</span><span class="s2">"</span><span class="w"> </span><span class="nv">name</span><span class="o">=</span><span class="s2">"</span><span class="k">$(</span>cleanname<span class="w"> </span><span class="s2">"</span><span class="nv">$@</span><span class="s2">"</span><span class="k">)</span><span class="s2">"</span>
<a id="rest_code_eed27f36decf4f3fa2a8ede786d10a79-4" name="rest_code_eed27f36decf4f3fa2a8ede786d10a79-4" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_eed27f36decf4f3fa2a8ede786d10a79-4"></a><span class="w"> </span><span class="nv">name</span><span class="o">=</span><span class="s2">"</span><span class="k">$(</span>logf<span class="w"> </span><span class="nv">$name</span><span class="k">)</span><span class="s2">"</span>
<a id="rest_code_eed27f36decf4f3fa2a8ede786d10a79-5" name="rest_code_eed27f36decf4f3fa2a8ede786d10a79-5" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_eed27f36decf4f3fa2a8ede786d10a79-5"></a><span class="w"> </span><span class="nb">printf</span><span class="w"> </span><span class="s1">'Logging to %s\n'</span><span class="w"> </span><span class="s2">"</span><span class="nv">$name</span><span class="s2">"</span>
<a id="rest_code_eed27f36decf4f3fa2a8ede786d10a79-6" name="rest_code_eed27f36decf4f3fa2a8ede786d10a79-6" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_eed27f36decf4f3fa2a8ede786d10a79-6"></a><span class="w"> </span><span class="o">(</span><span class="nb">echo</span><span class="w"> </span><span class="s2">"cmd was: </span><span class="nv">$cmd</span><span class="s2">"</span><span class="p">;</span><span class="w"> </span><span class="nb">time</span><span class="w"> </span><span class="s2">"</span><span class="nv">$@</span><span class="s2">"</span><span class="o">)</span><span class="w"> </span><span class="m">2</span>><span class="p">&</span><span class="m">1</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>tee<span class="w"> </span><span class="nv">$name</span>
<a id="rest_code_eed27f36decf4f3fa2a8ede786d10a79-7" name="rest_code_eed27f36decf4f3fa2a8ede786d10a79-7" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_eed27f36decf4f3fa2a8ede786d10a79-7"></a><span class="o">}</span>
</pre></div>
<p>So running the command</p>
<div class="code"><pre class="code bash"><a id="rest_code_1c24fb9803df4406a447d183dd70ea8f-1" name="rest_code_1c24fb9803df4406a447d183dd70ea8f-1" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_1c24fb9803df4406a447d183dd70ea8f-1"></a>exlog<span class="w"> </span>../configure<span class="w"> </span>--prefix<span class="o">=</span>/Users/tkb/sw/versions/groff/git
</pre></div>
<p>produces the file</p>
<div class="code"><pre class="code text"><a id="rest_code_e62052f01a4f47de9464d9b36be902d2-1" name="rest_code_e62052f01a4f47de9464d9b36be902d2-1" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_e62052f01a4f47de9464d9b36be902d2-1"></a>Log.configure-prefix-Users-tkb-sw-versions-groff-git_2021-07-07
</pre></div>
<p>and it contains the line</p>
<div class="code"><pre class="code text"><a id="rest_code_cf6b315b31e14382bb2325cd4fb874fe-1" name="rest_code_cf6b315b31e14382bb2325cd4fb874fe-1" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_cf6b315b31e14382bb2325cd4fb874fe-1"></a>cmd was: ../configure --prefix=/Users/tkb/sw/versions/groff/git
</pre></div>
<p>and running it again produces the file</p>
<div class="code"><pre class="code text"><a id="rest_code_12778cbd72f94443b5f88d43d2e1c68a-1" name="rest_code_12778cbd72f94443b5f88d43d2e1c68a-1" href="https://tkurtbond.github.io/posts/2021/07/07/logging-the-output-of-long-commands-run-multiple-times/#rest_code_12778cbd72f94443b5f88d43d2e1c68a-1"></a>Log.configure-prefix-Users-tkb-sw-versions-groff-git_2021-07-07_1
</pre></div>
<p>This code is available in a <a class="reference external" href="https://gist.github.com/tkurtbond/23255fede737eec89b1fd0e011566cb1">gist</a>.</p>
<p><em>Last edited: 2021-07-09 15:30:53 EDT</em></p>
<!-- Local Variables:
time-stamp-format: "%04y-%02m-%02d %02H:%02M:%02S %Z"
time-stamp-start: "\\*Last edited:[ \t]+\\\\?"
time-stamp-end: "\\*\\\\?\n"
time-stamp-line-limit: -20
End: -->Looping on 'dnf -y system-upgrade download' until it succeedshttps://tkurtbond.github.io/posts/2019/11/07/looping-on-dnf-y-system-upgrade-download-until-it-succeeds/2019-11-07T21:16:59-05:002019-11-07T21:16:59-05:00T. Kurt Bond<p>Fedora 31 is out, and fool that I am I'm upgrading to it.
Unfortunately, my DSL connection is slow and my DSL modem router is flaky.
With over 3000 packages to download,</p>
<div class="code"><pre class="code bash"><a id="rest_code_71f5c85201994bd49d5142bd9700ec92-1" name="rest_code_71f5c85201994bd49d5142bd9700ec92-1" href="https://tkurtbond.github.io/posts/2019/11/07/looping-on-dnf-y-system-upgrade-download-until-it-succeeds/#rest_code_71f5c85201994bd49d5142bd9700ec92-1"></a>dnf<span class="w"> </span>-y<span class="w"> </span>system-upgrade<span class="w"> </span>download<span class="w"> </span>--refresh<span class="w"> </span>--releasever<span class="o">=</span><span class="m">31</span>
</pre></div>
<p>is bound to die in the middle at least once, if not multiple times,
and with more than 6 hours estimated for the download to run I can't
sit watching it and restarting it every time it dies.</p>
<p>I tried running <code class="docutils literal">dnf</code> as the argument to a while loop, but was
unable to C-c to interrupt it when I <em>did</em> want to kill it since
<code class="docutils literal">dnf</code> caught the SIGINT and the loop started the <code class="docutils literal">dnf</code> command
over again before I could C-c the shell.</p>
<p>Here's the script I came up with to work around the issue:</p>
<p><a class="reference external" href="https://tkurtbond.github.io/listings/tryfedoraupdate.html">tryfedoraupdate</a> <a class="reference external" href="https://tkurtbond.github.io/listings/tryfedoraupdate">(Source)</a></p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://tkurtbond.github.io/posts/2019/11/07/looping-on-dnf-y-system-upgrade-download-until-it-succeeds/#rest_code_272e24b44d4d46f397a9cd947a7817c9-1"><code data-line-number=" 1"></code></a></td><td class="code"><code><a id="rest_code_272e24b44d4d46f397a9cd947a7817c9-1" name="rest_code_272e24b44d4d46f397a9cd947a7817c9-1"></a><span class="ch">#! /usr/bin/bash</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://tkurtbond.github.io/posts/2019/11/07/looping-on-dnf-y-system-upgrade-download-until-it-succeeds/#rest_code_272e24b44d4d46f397a9cd947a7817c9-2"><code data-line-number=" 2"></code></a></td><td class="code"><code><a id="rest_code_272e24b44d4d46f397a9cd947a7817c9-2" name="rest_code_272e24b44d4d46f397a9cd947a7817c9-2"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://tkurtbond.github.io/posts/2019/11/07/looping-on-dnf-y-system-upgrade-download-until-it-succeeds/#rest_code_272e24b44d4d46f397a9cd947a7817c9-3"><code data-line-number=" 3"></code></a></td><td class="code"><code><a id="rest_code_272e24b44d4d46f397a9cd947a7817c9-3" name="rest_code_272e24b44d4d46f397a9cd947a7817c9-3"></a><span class="k">while</span><span class="w"> </span>!<span class="w"> </span>dnf<span class="w"> </span>-y<span class="w"> </span>system-upgrade<span class="w"> </span>download<span class="w"> </span>--refresh<span class="w"> </span>--releasever<span class="o">=</span><span class="m">31</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://tkurtbond.github.io/posts/2019/11/07/looping-on-dnf-y-system-upgrade-download-until-it-succeeds/#rest_code_272e24b44d4d46f397a9cd947a7817c9-4"><code data-line-number=" 4"></code></a></td><td class="code"><code><a id="rest_code_272e24b44d4d46f397a9cd947a7817c9-4" name="rest_code_272e24b44d4d46f397a9cd947a7817c9-4"></a><span class="k">do</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://tkurtbond.github.io/posts/2019/11/07/looping-on-dnf-y-system-upgrade-download-until-it-succeeds/#rest_code_272e24b44d4d46f397a9cd947a7817c9-5"><code data-line-number=" 5"></code></a></td><td class="code"><code><a id="rest_code_272e24b44d4d46f397a9cd947a7817c9-5" name="rest_code_272e24b44d4d46f397a9cd947a7817c9-5"></a><span class="w"> </span><span class="nb">read</span><span class="w"> </span>-t<span class="w"> </span><span class="m">30</span><span class="w"> </span>-p<span class="w"> </span><span class="s2">"Continue? (y/n) "</span><span class="w"> </span>reply
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://tkurtbond.github.io/posts/2019/11/07/looping-on-dnf-y-system-upgrade-download-until-it-succeeds/#rest_code_272e24b44d4d46f397a9cd947a7817c9-6"><code data-line-number=" 6"></code></a></td><td class="code"><code><a id="rest_code_272e24b44d4d46f397a9cd947a7817c9-6" name="rest_code_272e24b44d4d46f397a9cd947a7817c9-6"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">((</span><span class="nv">$?</span>>128<span class="o">))</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://tkurtbond.github.io/posts/2019/11/07/looping-on-dnf-y-system-upgrade-download-until-it-succeeds/#rest_code_272e24b44d4d46f397a9cd947a7817c9-7"><code data-line-number=" 7"></code></a></td><td class="code"><code><a id="rest_code_272e24b44d4d46f397a9cd947a7817c9-7" name="rest_code_272e24b44d4d46f397a9cd947a7817c9-7"></a><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"timed out, continuing..."</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://tkurtbond.github.io/posts/2019/11/07/looping-on-dnf-y-system-upgrade-download-until-it-succeeds/#rest_code_272e24b44d4d46f397a9cd947a7817c9-8"><code data-line-number=" 8"></code></a></td><td class="code"><code><a id="rest_code_272e24b44d4d46f397a9cd947a7817c9-8" name="rest_code_272e24b44d4d46f397a9cd947a7817c9-8"></a><span class="w"> </span><span class="k">elif</span><span class="w"> </span><span class="o">[[</span><span class="w"> </span><span class="s2">"</span><span class="nv">$reply</span><span class="s2">"</span><span class="w"> </span><span class="o">=</span>~<span class="w"> </span><span class="o">[</span>Nn<span class="o">]</span><span class="w"> </span><span class="o">]]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://tkurtbond.github.io/posts/2019/11/07/looping-on-dnf-y-system-upgrade-download-until-it-succeeds/#rest_code_272e24b44d4d46f397a9cd947a7817c9-9"><code data-line-number=" 9"></code></a></td><td class="code"><code><a id="rest_code_272e24b44d4d46f397a9cd947a7817c9-9" name="rest_code_272e24b44d4d46f397a9cd947a7817c9-9"></a><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"Exiting..."</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://tkurtbond.github.io/posts/2019/11/07/looping-on-dnf-y-system-upgrade-download-until-it-succeeds/#rest_code_272e24b44d4d46f397a9cd947a7817c9-10"><code data-line-number="10"></code></a></td><td class="code"><code><a id="rest_code_272e24b44d4d46f397a9cd947a7817c9-10" name="rest_code_272e24b44d4d46f397a9cd947a7817c9-10"></a><span class="w"> </span><span class="nb">exit</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://tkurtbond.github.io/posts/2019/11/07/looping-on-dnf-y-system-upgrade-download-until-it-succeeds/#rest_code_272e24b44d4d46f397a9cd947a7817c9-11"><code data-line-number="11"></code></a></td><td class="code"><code><a id="rest_code_272e24b44d4d46f397a9cd947a7817c9-11" name="rest_code_272e24b44d4d46f397a9cd947a7817c9-11"></a><span class="w"> </span><span class="k">else</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://tkurtbond.github.io/posts/2019/11/07/looping-on-dnf-y-system-upgrade-download-until-it-succeeds/#rest_code_272e24b44d4d46f397a9cd947a7817c9-12"><code data-line-number="12"></code></a></td><td class="code"><code><a id="rest_code_272e24b44d4d46f397a9cd947a7817c9-12" name="rest_code_272e24b44d4d46f397a9cd947a7817c9-12"></a><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"Continuing..."</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://tkurtbond.github.io/posts/2019/11/07/looping-on-dnf-y-system-upgrade-download-until-it-succeeds/#rest_code_272e24b44d4d46f397a9cd947a7817c9-13"><code data-line-number="13"></code></a></td><td class="code"><code><a id="rest_code_272e24b44d4d46f397a9cd947a7817c9-13" name="rest_code_272e24b44d4d46f397a9cd947a7817c9-13"></a><span class="w"> </span><span class="k">fi</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://tkurtbond.github.io/posts/2019/11/07/looping-on-dnf-y-system-upgrade-download-until-it-succeeds/#rest_code_272e24b44d4d46f397a9cd947a7817c9-14"><code data-line-number="14"></code></a></td><td class="code"><code><a id="rest_code_272e24b44d4d46f397a9cd947a7817c9-14" name="rest_code_272e24b44d4d46f397a9cd947a7817c9-14"></a><span class="k">done</span>
</code></td></tr></table></div><p>This way I can stop the script easily, but if it dies itself it will
continue after a timeout.</p>Case-insenstive filename completion with bash and emacshttps://tkurtbond.github.io/posts/2009/04/24/case-insenstive-filename-completion-with-bash-and-emacs/2009-04-24T13:59:07-05:002009-04-24T13:59:07-05:00T. Kurt Bond<p>It's strange, I know, that while I like case sensitive filenames, I
don't actually want to be bothered matching the case exactly when I'm
using tab completion. Fortunately, <span class="program">emacs</span> and
<span class="program">bash</span> both accommodate my whims. For bash, add</p>
<div class="code"><pre class="code bash"><a id="rest_code_68b5f2e0d5a34f9bae8a6b80f7629143-1" name="rest_code_68b5f2e0d5a34f9bae8a6b80f7629143-1" href="https://tkurtbond.github.io/posts/2009/04/24/case-insenstive-filename-completion-with-bash-and-emacs/#rest_code_68b5f2e0d5a34f9bae8a6b80f7629143-1"></a><span class="nb">set</span><span class="w"> </span>completion-ignore-case<span class="w"> </span>on
</pre></div>
<p>to your <code class="docutils literal"><span class="pre">~/.inputrc</span></code> file. For emacs, add</p>
<div class="code"><pre class="code emacs-lisp"><a id="rest_code_4db03e78b788481889da853992886229-1" name="rest_code_4db03e78b788481889da853992886229-1" href="https://tkurtbond.github.io/posts/2009/04/24/case-insenstive-filename-completion-with-bash-and-emacs/#rest_code_4db03e78b788481889da853992886229-1"></a><span class="p">(</span><span class="nv">read-file-name-completion-ignore-case</span><span class="w"> </span><span class="no">t</span><span class="p">)</span>
</pre></div>
<p>to your emacs initialization files. Of course, if want to get rid of
all completion case sensitivity, you need</p>
<div class="code"><pre class="code emacs-lisp"><a id="rest_code_823d50b4a6c1424e9b126a91bbbb5e65-1" name="rest_code_823d50b4a6c1424e9b126a91bbbb5e65-1" href="https://tkurtbond.github.io/posts/2009/04/24/case-insenstive-filename-completion-with-bash-and-emacs/#rest_code_823d50b4a6c1424e9b126a91bbbb5e65-1"></a><span class="p">(</span><span class="k">setq</span><span class="w"> </span><span class="nv">completion-ignore-case</span><span class="w"> </span><span class="no">t</span><span class="p">)</span>
</pre></div>
<p>too.</p>Cygwin setup crashes updating bashhttps://tkurtbond.github.io/posts/2008/11/26/cygwin-setup-crashes-updating-bash/2008-11-26T15:57:51-05:002008-11-26T15:57:51-05:00T. Kurt Bond<p>Thanks to the wonders of Google and <a class="reference external" href="http://rubenlaguna.com/wp/2007/11/05/cygwin-setupexe-crashes-whem-upgrading-packages/">Ruben</a> I finally found the answer:
remove (you'll want to make a backup copy before you remove it,
though) <code class="docutils literal">/etc/setup/bash.lst.gz</code> which apparently had become
corrupted.</p>
<p>According to a comment on that post, running <code class="docutils literal">gunzip <span class="pre">-t</span></code> on all
files in <code class="docutils literal">/etc/setup</code> will tell you which setup files have been
corrupted.</p>