1. 9

What unique compositions of common Unix commands do you use often?

Here’s one I use to see which commands I’m running most often:

alias mostusedcomms="history \
    | awk '{CMD[\$2]++;count++;}END { for (a in CMD)print CMD[a] \" \" CMD[a]/count*100 \"% \" a;}' \
    | grep -v \"./\" | column -c3 -s \" \" -t | sort -nr | nl |  head -n20"

Or one which prints giant text to the screen, to let me know when long running jobs are done:

#!/bin/bash

if [ $# -eq 1 ]; then
    MSG="$1"
else
    MSG="done"
fi
osascript -e "tell application \"Quicksilver\" to show large type \"$MSG\""
  1.  

  2. 3

    When I’m in doubt about shell expansion, I usually run echo-eol which is like this:

    #!/usr/bin/perl -w
    #
    # Just to verify how command line arguments work in weird cases.
    
    use strict;
    use warnings;
    
    my $i = 0;
    foreach my $arg (@ARGV) {
        printf "%03d> '%s'\n", $i++, $arg;
    }
    

    Also, since at work I’ve got a secondary monitor, I use the workscreen commands, which is a shorthand for xrandr:

    #!/bin/sh
    
    export LAPTOP="LVDS-1"
    export SCREEN="DP-1"
    
    case $1 in
    
        "dual")
            xrandr --output $SCREEN --auto
            xrandr --output $LAPTOP --auto
            xrandr --output $SCREEN --above $LAPTOP
        ;;
    
        "laptop")
            xrandr --output $LAPTOP --auto
            xrandr --output $SCREEN --off
        ;;
    
        "screen")
            xrandr --output $SCREEN --auto
            xrandr --output $LAPTOP --off
        ;;
    
        *)
            echo "laptop | screen | dual"
        ;;
    
    esac
    

    As Vim user, I don’t like caps lock and I prefer esc instead…

    #!/bin/sh
    
    case $1 in
      "enable")
        xmodmap -e 'clear lock'
        xmodmap -e 'keycode 0x42 = Escape'
        ;;
      "disable")
        xmodmap -e 'keycode 0x42 = Caps_Lock'
        xmodmap -e 'add lock = Caps_Lock'
        ;;
      *)
        echo "usage: $0 enable|disable"
    esac
    

    …those are the most interesting home-made commands of mine. I’ve got some other commands which are more complex, but they’re very specific for my routine.

    1. 2

      A long time ago, I started putting all the random C utilities and shell scripts I was writing for myself in a git repo.

      I haven’t really used most of those utilities in a while. This post prompted me to go back and document some of them more properly. Some useful ones are

      webpipe.sh - Pipe standard input into an HTML file and open it in the browser. So you could do something like redcarpet README.md | webpipe.sh to see what your README will look like on Github.

      pdfcat.sh - Basically an alias for a hairy invocation of GhostScript that will combine several PDF documents together.

      lrange - The middle sibling of head and tail; lrange a b file.txt will print the lines a-b inclusive from the file to standard output.

      1. 2

        I frequently use the classic overwrite from K&P:

        #!/bin/sh
        # overwrite:  copy standard input to output after EOF
        # (final version)
        
        # set -x
        
        case $# in
        0|1)    echo 'Usage: overwrite file cmd [args]' 1>&2; exit 2
        esac
        
        file=$1; shift
        new=/tmp/$$.new; old=/tmp/$$.old
        trap 'rm -f $new $old; exit 1' 1 2 15   # clean up files
        
        if "$@" >$new       # collect input
        then
            cp $file $old   # save original file
            trap 'trap "" 1 2 15; cp $old $file # ignore signals
                  rm -f $new $old; exit 1' 1 2 15   # during restore
            cp $new $file
        else
            echo "overwrite: $1 failed, $file unchanged" 1>&2
            exit 1
        fi
        rm -f $new $old
        

        For example, while json_reformat < test.json > test.json won’t work, overwrite test.json json_reformat < test.json will.

        I also use this handy utility for converting plain text files wrapped at 80 columns to PDF, with a header that includes the file name: (requires enscript and ps2pdf from ghostscript)

        #!/bin/sh
        
        first=0
        for f; do
          if [ $first != 0 ]; then
            echo '--------------------------------------------------------------------------------'
            first=1
          fi
        
          echo "File: " $f
          echo
          cat $f
        done | enscript --font="DejaVuSansMono11" --media Letter \
                 --margins=25:25:: \
                 --header='$n|Page $% of $=' -o - | ps2pdf - -
        

        Finally, I bind edit_textbuf to Super-Shift-e, which automatically loads text from a textarea in a browser into vim in a terminal. (And when you quit vim, it overwrites the textarea with your modifications.) I believe the script can be configured for other terminals/editors.

        1. 2

          The projectors at my school are all connected to some hub thing which make my Arch install only detect 800x600 as a possible resolution (sometimes smaller). I got sick of writing the commands to force it to output at 1920x1080 and mirror my laptop’s built in display so I put together a script to do it for me. It’s just three xrandr commands, but it’s so nice.

          I also have a tiny python script to upload a specified file to a “stuff I want to share quickly” site.

          1. 2

            https://github.com/leifwalsh/df/tree/master/bin

            All of that is cruft I no longer use, except for mypass:

            #!/usr/bin/env bash
            
            if [[ $(uname -s) = "Darwin" ]]
            then
                COPY=pbcopy
            else
                COPY="xclip -sel clipboard"
            fi
            SHA256=$(which sha256sum)
            if [ $? != 0 ] ; then
                SHA256=$(which sha256)
            fi
            
            if [[ $# -ne 1 ]]; then echo "Usage: $(basename $0) <site>" && exit 2; fi
            (gpg -q -d ~/.passwd.gpg; echo "$1") | $SHA256 | cut -c-16 | xargs echo -n | $COPY
            

            It’s my own little 1password/lastpass/keepass replacement.

            1. 2

              I’ve dropped Larry's filename fixer into ~/bin for as long as I can remember. It’s from the Perl Cookbook and that Larry.

              #!/usr/bin/perl -w
              # rename - Larry's filename fixer
              $op = shift or die "Usage: rename expr [files]\n";
              chomp(@ARGV = <STDIN>) unless @ARGV;
              for (@ARGV) {
                      $was = $_;
                      eval $op;
                      die $@ if $@;
                      rename($was,$_) unless $was eq $_;
              }
              

              It lets you apply perlre to file renaming operations:

              $ rename 's/foo-(\d+)/$1-bar/' *.baz
              

              More examples and notes here.

              Unfortunately my ~/bin also contains cvs-wtf-arg:

              #!/bin/sh
              cvs up 2>/dev/null | grep "^\?"
              

              because I work on one project that still uses CVS. If you know why I need this then I apologise.

              1. [Comment removed by author]

                1. 2

                  I use this (in my ~/.gitconfig) to prevent myself having to write out the remote names:

                  [alias]
                    mpush = !git remote | xargs -J % -L 1 git push % master
                  
                  1. 1

                    If you named it “git-pushall” or something then you could use “git pushall” like any other git command, fwiw.

                    1. 1

                      Would that work? Wouldn’t you need to call git-pushall not git pushall? Because at least for me, I don’t have a git-push or git-pull command, which makes me think they’re just nice ways to separate sections of the manual.

                      You could write an alias, which would let you use git pushall:

                      [alias]
                        pushall = "!git push digitalocean master && git push github master && git push bitbucket master"
                      
                      1. 2

                        It works, give it a try. The main git binary will look for a git-FOO executable for you.

                        Because at least for me, I don’t have a git-push or git-pull command

                        You actually do, it’s just not on your standard path. git knows where to look for it, on my system for example there is /usr/lib/git-core/git-pull and that git-core dir is full of the same.

                  2. 1

                    I get a lot of mileage from my git-deploy script. It’s pretty simple, just force-pushes the current HEAD onto a given remote.

                    #!/bin/bash
                    git push $1 +HEAD:master
                    git fetch $1
                    git push origin --tags
                    

                    This assumes you use git for deployments. You’ll take some serious heat from your fellow developers if you used this on a remote that isn’t a “functional” repository (I classify most repos as archival, deployments as functional).

                    The latter two lines fetch the history of the remote and push any auto-generated deployment tags with the origin.This useful when git log --decorateing to see what is live compared to what is in dev.

                    1. 1

                      I rarely remember what our latest release was. I keep this around under git-latest-tag so I can quickly check. It relies on GNU sort’s version sort, so for Mac users gsort is available on Homebrew in the coreutils package.

                      #!/bin/sh
                      PREFIX="$1"
                      git tag | grep "^$PREFIX[0-9]" | gsort -V | tail -n1
                      

                      I also spend a lot of time managing Redis instances, so I keep this in redis-delkeys. It removes all the keys in a database matching a pattern. It takes the same switches as redis-cli for host, port, and db number. I have a couple variants of it for different tasks (moving keys between two different instances, etc.), but they all have this general structure.

                      #!/bin/sh
                      set -e
                      HOST="localhost"
                      PORT="6379"
                      DB="0"
                      while getopts "h:p:n:" opt; do
                          case $opt in
                              h)  HOST=$OPTARG;;
                              p)  PORT=$OPTARG;;
                              n)  DB=$OPTARG;;
                              \?) echo "invalid option: -$OPTARG" >&2; exit 1;;
                          esac
                      done
                      shift $(( $OPTIND -1 ))
                      PATTERN="$@"
                      if [ -z "$PATTERN" ]; then
                          echo "pattern required" >&2
                          exit 2
                      fi
                      redis-cli -h $HOST -p $PORT -n $DB --raw keys $PATTERN |
                          xargs redis-cli -h $HOST -p $PORT -n $DB del
                      
                      1. 1

                        Browse cvsweb for current directory or named file:

                        #!/bin/sh
                        firefox -new-window http://www.openbsd.org/cgi-bin/cvsweb/`cat CVS/Repository`/$1
                        

                        Simple alternative to ag or ack:

                        #!/bin/sh
                        target=$1
                        shift
                        places=$@
                        if [ -z "$places" ] ; then places=. ; fi
                        find $places  \! \( -path "*/obj/*" -or -path "*/CVS/*" \) \! \( -name "*.o" -or -name "*.orig" -or -name ".#*" \) \! -type l -print0 | xargs -0 grep "$target"