Shell scripting for personal productivity

 

In an edX course on Unix tools I am running these weeks, I got asked for ideas on how shell scripts can be useful. This is a very interesting question, because the course focuses mainly on performing one-off tasks in the areas of software development, data engineering, and system administration, rather than automation through shell scripts. Here’s how I’m using shell scripting to enhance my personal productivity. I’ll post further installments regarding software development and system administration.

I have a $HOME/bin directory where I keep my personal executable files. I maintain and distribute this on hosts I’m using via Git. The directory contains scripts such as the following. (Where the scripts are relatively small, somewhat portable, and of general interest I also show their contents.) Note that some of the operations are CygWin-specific and that many scripts can be enhanced to be made more robust for use in a production environment.

beep

Make a beep sound; I run it to get notified when a long process has finished; e.g. make ; beep or wait ; beep.

!#/bin/sh
printf '\a'`

bib

Fetch BibTeX entries from my global BibTeX files matching the specified search term.

btags

Extract the key names of BibTeX entries as tags that my editor (vim) can use to jump directly to the entry from its citation.

#!/bin/bash
awk '/^@/{ printf "%s\t%s\t?^%s?\n", $2, FILENAME, $0}' FS=$'[,{ \t(]*' "$@" |
LC_COLLATE=C sort >tags

csvawk

Run awk with the specified program argument on a CSV (comma separated values file); e.g. csvawk '{print $2 - $3}' list.csv.

#!/bin/sh
prog="$1"
shift
awk 'BEGIN {FPAT = "([^,]+)|(\"[^\"]+\")"}'"$prog" "$@"

decimal

Add decimal separators to long numbers; e.g. ls -l | decimal. (I know about ls -h; I use this mainly when preparing tables with numbers for publication.)

#!/bin/sed -Ef

:a
# Add a , after a digit followed by three digits followed by non-digit or EOL
s/([0-9])([0-9]{3})([^0-9]|$)/\1,\2\3/

# Try the replacement again if the replacement succeeded
ta

fixlong

Fix text with long lines by starting each sentence in a new line (as I advocate in my advice for writing LaTex documents), folding the rest, and removing carriage returns.

#!/bin/sh
# Remove carriage returns (keeping line feeds)
tr -d \\r |
# Start sentences on a new line
sed 's/\.  */.\n/g' |
# Fold (but don't join) remaining long lines
fmt -s

ghopen

Open the GitHub page associated with the repository in the current directory. The cygstart command is CygWin-specific, but there are similar commands in all GUI environments: kde-open, gnome-open, open (macOS).

#!/bin/sh
cygstart $(git remote -v | sed 's|:|/|;s|.*git@|https://|;s/\.git .*//')

home-install

Install my personal environment from its Git repo when I first setup a new host. It includes configuration for Bash, my editor (vim), the personal files, and so on.

kml2gpx

Convert Google Earth KML paths into GPX for uploading them to Strava.

makeics

Create an iCalendar file for a specified event.

mdview

View a nicely formatted version of a Markdown document in my web browser.

#!/bin/sh
# View a markdown file

TEMPFILE=c:/tmp/md-$$.html

if ! [ "$1" ] ; then
  echo "Usage: $0 file.md" 1>&2
  exit 1
fi

pandoc --metadata pagetitle="$(basename $1)" --css=file:///C:/dds/home/lib/pandoc.css -s "$1" -o $TEMPFILE
cygstart $TEMPFILE
sleep 1
rm -f $TEMPFILE

mkabstract

Extract an abstract from a LaTeX document in text form, suitable for pasting it in a paper submission form.

#!/bin/sed -nf
/\\begin{abstract}/,/\\end{abstract}/ {
        /{abstract}/d
        s/\\textit{//
        s/}//
        s/\\,/,/g
        /^%.*/d
        s/\([^\\]\)%.*/\1/;
        s/\\%/%/g
        s/\\\\//
        p
}

pdfsign

Add my digital signature to the specified PDF document.

phone

Display a person’s phone numbers given their name. It obtains the phone number from the latest backup copy of my cell phone’s contact list.

rcs2git

Convert ancient RCS repositories into Git ones.

recent

Show my recent Git commit activity; I use it to summarize what I’ve been working on in update meetings.

#!/bin/sh
find /home/dds/ -type d -name .git |
while read d ; do
  git --git-dir=$d log --author=dds@aueb.gr --oneline --since='two weeks' |
  sed "s|^|$d: |;s/\/\.git://;s/^.*\/\([^/]*\):/\1:/"
done |
awk '{print $1}' |
sort |
uniq -c |
sort -rn |
head -30

rvim

(Revisionist vim.) Edit the specified files, maintaining their timestamp.

#!/bin/sh
for i in "$@"; do
  FILE="$i"
  MTIME=$(stat -c %Y "$FILE")
  vim "$FILE"
  touch -d @$MTIME "$FILE"
done

setup-ssh-host

Setup a remote host for logging in via ssh. I maintain a hierarchy of ssh keys based on how much I trust the physical and administrative security of a remote host. This script sets up the appropriate keys.

terminal-title

Set up the title of the terminal window I’m using to my login name, host name, name of the Git directory (if available), and the current directory.

#!/bin/bash

HOSTNAME=$(hostname -s)
if [ "$HOSTNAME" = "macpro" ] ; then
  HOSTNAME=''
else
  HOSTNAME="$HOSTNAME:"
fi

# Set the terminal title to the specified argument
set_title()
{
  printf "\033]0;%s%s\007" "$HOSTNAME" "$1"
}

# Current directory is a Git directory
if [ -d .git ] ; then
  set_title "${PWD##*/}"
  exit 0
fi

# Loop to top until a Git directory is found
CURRENT_DIR=${PWD##*/}
while : ; do
  cd ..
  if [ -d .git ] ; then
    set_title "${PWD##*/}...$CURRENT_DIR"
    exit 0
  fi
  # Root directory?
  if [ . -ef .. ] ; then
    set_title "$CURRENT_DIR"
    break
  fi
done

wincd

Change the current directory to that specified by a Windows shortcut Uses the Outwit readwinlink command.

#!/bin/sh
cd $(cygpath $(readwinlink $1 | tr -d \\r))

update-web

Update my web home pages from their locally-maintained content.

worldtime

Print the specified (or current) time in other time zones and the converse. I demonstrate this in the course.

Comments   Toot! Share


Last modified: Monday, March 23, 2020 11:43 am

Creative Commons Licence BY NC

Unless otherwise expressly stated, all original material on this page created by Diomidis Spinellis is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.