1. 1

    The main part of my $HOME is a hierarchy:

    std/bin
    std/cfg
    std/cfg/templates
    std/lib
    std/lib/perl
    std/lib/perl/...
    std/lib/sh
    std/lib/vim
    std/lib/vim/...
    std/libexec
    

    which contains almost all of my configuration. Various dotfiles like .bashrc and .vimrc are symlinked into $HOME from std/bin. I replicate this hierarchy across 1000+ servers to give me my standard environment on those servers. I have a separate $HOME/bin for local additions applicable to only a single server environment. Almost all of my non-dotfile $HOME is symlinks.

    1. 19
      jtm@x1c ~ % ls
      TODO acme aux bin doc down git go mail mnt music rom www xen 
      
      • acme - additional scripts for acme.
      • aux - synonymous with “junk”.
      • doc - images, documents, slides, etc.
      • down - downloads
      • mail - emails in Maildir format.
      • www - source code for a static site.
      • xen - vm configurations.

      I’ve been meaning to add a cron job to delete anything in down that’s older than three days.. that folder tends to blow up.

      To keep junk from accumulating in $HOME, I use a shell function called “t” that will automatically cd to a temporary scratch space, so I don’t have to think about cleaning up junk that I don’t intend to keep. I use this almost every day.

      function t {
        cd $(mktemp -d /tmp/$1.XXXX)
      }
      
      1. 15

        Instead of a t function, I have a ~/tmp folder.

        Because ~/tmp is persistent, I end up with stuff in there that I’m afraid to delete, so I made a ~/tmp/tmp for stuff that’s actually temporary.

        Because ~/tmp/tmp is persistent, I occasionally end up with stuff in there that I'm afraid to delete. I once just needed a temp folder quickly, but didn't feel like stuff in ~/tmp was safe to delete yet, so I made a ~/tmp/tmp/tmp`.

        I should add that t function to my rc.

        1. 3

          Ooo, I love the t function. I make temp dirs for stuff all the time. So simple, but really helpful - thanks for sharing!

          1. 2

            I have a similar j function which creates a named (default: junk) subdirectory in the current directory and cds to it. There is a corresponding jjj function which is essentially rm -fr junk. Because the new directory is under the current directory, I find it is easier to reference the original directory with .. rather than using "$OLDPWD".

          1. 1

            Why use a loop at all? In java: foo = Joiner.on(”,”).join(bar);

            My real answer is that high-level code is better than low-level code, unless there’s some really important justification for preferring a low-level implementation. That you know how to write the low-level code doesn’t mean that you should. What you should do is write lucid straight-line code (few or no indentation changes) and use abstractions to make that simple for yourself.

            1. 4

              The real real answer is Json requiring that there must be no last comma causes a huge number of programmers a small twinge of pain each.

              void damnJson( char ** string, size_t len)
              {
                 if( len == 0) // You're always going to have to have a horrid corner case
                    return; // The early return pattern coupled with small functions equals cleaner code.
              
                 // The Happy Path
                 fputs( string[0], stdout);
                 for(int i=1; i < len; i++) { // Note the offset by one start to loop.
                    fputc( ',', stdout);
                    fputs( string[i], stdout);
                 }
              }
              
              1. 2

                And that’s why language designers who care about the language’s “user experience” allow for a final trailing delimiter in lists. Perl does this and every DSL I design also does this, for exactly this reason. @arnt: I agree that using a higher level construct can often eliminate the problem. But sometimes (e.g. when streaming data), that’s not possible.

                1. 2

                  And go mandates it, which is even nicer imo.

            1. 3

              sh -c 'sep=; for f in {a..g} ;do printf "$sep%s" $f; sep=,; done; echo'

              1. 3

                Sure, this is an example of bringing state into the loop from outside: before your first time through the loop, sep=; #semi-colon is a character the shell takes so this is like sep=. After, sep=,, so printf gets the ,.