.bashrc.org 12 KB

.bashrc

About this .bashrc file

Intro

This is George Jones' .bashrc file as an literate programming file in emacs org mode using babel blocks.

To generate the actual .bashrc

This .bashrc.org file must be processed to generate the actual .bashrc It can be processed interactively to generate .bashrc via org-babel-tangle-file or from the command line as

emacs --batch --eval "(require 'org)" --eval '(org-babel-tangle-file ".bashrc.org")'

Permanent changes must be made to the .org version, as the actual .bashrc will be overwritten when the .org version is "compiled"

Debugging

In most bash files I do

set -e
set -u

but there are problems setting it in .bashrc. An error then causes you to exit the shell entirely (not what you want), and there are several constructs that cause warnings due to undefined variables (these can/probably should be fixd)

Set

export DEBUG=1

to enable debugging output from the debug helper function.

The actual executable .bashrc

Helper functions

I define a few syslog-ish helper functions to print warnings, errors, etc.

#PROG=`basename "$0" | tr -d '\n'`  # normal setting
PROG="bashrc" # setting for bashrc due to errors

function info()  { echo ${PROG}\: info: "$@" 1>&2; }
function warn()  { echo ${PROG}\: warning: "$@" 1>&2; }
function error() { echo ${PROG}\: error: "$@" 1>&2; }
function debug() { [[ -v DEBUG ]] && echo ${PROG}\: debug: "$@" 1>&2 || true ; }
function die()   { echo ${PROG}\: fatal: "$@" 1>&2 && exit 1; }

Set a reasonable default prompt

Here I set a reasonable default prompt that includes timestamp, username, host and current directory:

export PS1="\# [\t] \u@\h \W/ $ "

Misc aliases

Define various aliases that I use

alias rm='	rm -i'
alias ag='	alias | grep -i'
alias eg='	printenv | grep -i'
alias hg='	history | grep -i'
alias ht='	history | tail'
alias fpg='	find . -print | egrep -i'
alias egi='	egrep -i'
alias psg='	/bin/ps -auxww | grep'
alias p8='	ping -c 3 8.8.8.8' # make sure routing works
alias pp='	ping -c 3 port111.com' # make sure dns and routing work
alias locate='locate -r'

cd commands that use/print the directory stack

These aliases support pushd/popd/dirs like functionality while listing one directory per line

I like to keep a "stack" of directories so I can work on one thing then "pop" back to where I was. pushd an popd support this, and dirs lists the directories, but I prefer to have them listed one per line.

function dirl() {
   # "DIR"ectory "L"ist directory stack, one per line
   # Usage: dirl

   for d in `dirs`; do echo $d; done
}

function dirc() {
   # "DIR"ectory "C"onnect - connect to directory and list stack
   # Usage: dirc [DIR

   pushd ${1:-"$HOME"} > /dev/null
   dirl
}

function dirp () {
   # "DIR"ectory "P"op - pop N entries off the directory stack
   # Usage: dirp [N]
   #
   # OLD:
   #   alias  dirp='popd > /dev/null && dirl'
   for i in `seq ${1:-"1"}`; do
       debug "dirl: popd. i is $i"
       popd > /dev/null;
   done
   dirl
}

alias cd=pushd

Misc functions


function gf() {
# grep-find: grep for patterins in files via find
#
# Usage: gf patterns [files [days]]
#
# Examples:
#   gf findMeAnywhere
#   gf findMeInTextFiles '*.txt'
#   gf findMeInTextFiles .txt
#   gf BEGIN\|END .org 30

local files=""
local days="365"

set -o noglob

# First arg is pattern(s) for egrep
if [ -z ${1+x} ]; then
 echo 'gf needs string(s) to search for ' 1>&2
 info "Usage: gf patterns [files [days]]"
 return 1
fi

# Second arg (if present) is files for find.  No globbing, so "*.txt" OK
if [ ! -z ${2+x} ]; then
 if [[ "$2" =~ ^\. ]]; then
   # Special case: treat ".foo" as "*.foo"
   # Avoids needing to quote on command line
   files="-name *$2"
 else
   files="-name ${2}"
 fi
fi

# $3 (if present) is find -mtime arg, default 365
if [ ! -z ${3+x} ]; then
 days="${3}"
fi

# set -x
find . -type f -mtime -${days} $files -exec egrep --color -H -i "${1}" \{\} \;
# set +x

set +o noglob
}

Bash history functions and settings


# Preserve history across sesssions
#
# http://unix.stackexchange.com/questions/1288/preserve-bash-history-in-multiple-terminal-windows
#
export HISTCONTROL=ignoredups:erasedups  # no duplicate entries
export HISTSIZE=100000                   # big big history
export HISTFILESIZE=100000               # big big history
shopt -s histappend                      # append to history, don't overwrite it

# Save and reload the history after each command finishes
export PROMPT_COMMAND="history -a; history -c; history -r;"


function hgt() {
   # hgt == "history grep (for arg) tail"
   #echo "Histroy Grep tail"

   if [ -z ${1+x} ]; then
       echo 'hgt needs an argument' 1>&2
       return 1
   fi

   history | grep -i "$1" | tail
   return 0
}

Set the hostnane, timezone and local

Set HOSTNAME if ~/etc/hostname exists

if [ -e ${HOME}/etc/hostname ]; then
    export HOSTNAME=`cat ${HOME}/etc/hostname`
elif [ -e /etc/hostname ]; then
    export HOSTNAME=`cat /etc/hostname`
else
    export HOSTNAME="unknown"
fi

# Set timezone if ~/bin/tz.sh exists

# NEW, if neeeed?
#
# https://linuxize.com/post/how-to-set-or-change-timezone-in-linux/
#
# OLD:
#
# if [ -e ~/bin/tz.sh ]; then
#     echo Setting timezone.
#     source ~/bin/tz.sh # should be in ~/rc.local
# fi

# STILL NEEDED?
#
# Set local for numeric output
LOCAL=`locale -a | grep -i en_us | head -1`
if [[ "$LOCAL" != "" ]]; then export LC_NUMERIC="$LOCAL"; fi

Set up ssh agent

Add keys by hand if needed via

ssh-add ~/.ssh/id_*
if [ -e ~/bin/sshagent ]; then
    source ~/bin/sshagent
fi

Copy stdin to clipboard

if [[ "$OSTYPE" == "linux-gnu"* ]]; then
  alias 2clip='xclip -selection c'
  alias 3clip='printf %s "$(cat /dev/stdin)" | xclip -selection c'  # no final \n
elif [[ "$OSTYPE" == "darwin"* ]]; then
  alias 2clip='pbcopy'
fi

Path functions

These path* functions add and remove elements to PATH. They insure that entries are unique. They allow you to place a path first or last in the order (e.g. so that ~/bin comes before /usr/local/bin)

pathrm() {
    # remove an item from the path
    if [ -d "$1" ]; then
        removeThis="`echo $1 | sed -e 's#/#\\\/#'g`"
        newPath=`echo $PATH | awk -v RS=: -v ORS=: "/$removeThis/ {next} {print}" | sed 's/[ :]*$//g'`
        export PATH=$newPath
    fi
}


pathlast() {
    # add path to the end if not there
    if [ -d "$1" ] && [[ ":$PATH:" != *":$1:"* ]]; then
        export PATH="${PATH:+"$PATH:"}$1"
    fi
}


pathfirst() {
    # add path to the front if not there
    if [ -d "$1" ] && [[ ":$PATH:" != *":$1:"* ]]; then
        export PATH="$1:${PATH}"
    fi
}

path() {
  # show path
  echo $PATH
}

# show path, one entry per line
alias pathcat="echo $PATH | sed 's/:/\n/g'"


# Be sure we have a few specific paths if they exist

pathlast $HOME/bin
pathlast /usr/local/bin
pathlast /opt/bin

source ~/rc.local/*.sh to do non-general bash setup

Execute any .sh files in ~/rc.local/*.sh

This allows me to split out setup for aliases and commands that only get used on certian systems or in certian contexts (git, go, mail, blog..)


if [ -d ${HOME}/rc.local ]; then
    for rcfile in $(find ${HOME}/rc.local -name \*.sh); do
        debug running localrc ${rcfile}
        source ${rcfile}
    done
fi

Invoking emacs

alias emacs='setsid emacs'

# from http://stuff-things.net/2014/12/16/working-with-emacsclient/

if [ -z "$SSH_CONNECTION" ]; then
    export EMACSCLIENT=emacsclient
    alias ec="$EMACSCLIENT -c -n"
    export EDITOR="$EMACSCLIENT -c"
    export ALTERNATE_EDITOR=""
else
    export EDITOR=$(type -P emacs || type -P ed)
fi
export VISUAL=$EDITOR

ls aliases


# coloring for ls functions

if [[ "$OSTYPE" == "linux-gnu" ]]; then
    color="--color";
else
    color=""
fi

BIN_LS=/bin/ls
alias ls='	ls '$color' -a'


# Long List Reverse Tail
function llrt() { ls -lrt $color ${*:-}; }

# Long List Time
function llt() { ls -lt $color ${*:-}; }

# Long List Time, More
function lltm() { ls -lt $color ${*:-} | more; }

# Long List Time, Less
function lltl() { ls -alt $color ${*:-} | more; }

# Long List Time, Head
function llth() { ls -lt $color ${*:-} | head; }

# Long List Time, Tail
function lltt() { ls -alt $color ${*:-} | tail; }


# List Sort Size
function lss() { ls -a1s $color ${*:-} | sort -n; }

# List Sort Size Reverse
function lssr() { ls -a1s $color ${*:-} | sort -nr; }

Aliases for viewing the newest file in a directoy


function nf ()
{
    # list the newest file in the current directory
    NF=`find ${1:-.} -maxdepth 1 -type f -print0 | xargs -0 ls -1t  |  head -1;`;
    echo ${NF:-/dev/null} | sed "s/ /\\\ /g"
}


# new file tail file
function nftf { NF=`nf ${1:-.}`; debug NF $NF;  echo "$NF" | xargs tail -f  ; }

# new file tail
function nft { NF=`nf ${1:-.}`; debug NF $NF;  echo "$NF" | xargs tail  ; }

# new file head
function nfh { NF=`nf ${1:-.}`; debug NF $NF;  echo "$NF" | xargs head  ; }

# new file less
function nfl { NF=`nf ${1:-.}`; debug NF $NF;  echo "$NF" | xargs less  ; }

# new file cat
function nfc { NF=`nf ${1:-.}`; debug NF $NF;  echo "$NF" | xargs cat  ; }

# new file ls
function nfls { NF=`nf ${1:-.}`; debug NF $NF;  echo "$NF" | xargs ls -A1t  ; }

# new file ls -l
function nflsl { NF=`nf ${1:-.}`; debug NF $NF;  echo "$NF" | xargs
ls -Atl  ; }

viewing files

Notes on setting up file/mime type associations can be found at

https://unix.stackexchange.com/questions/77136/xdg-open-default-applications-behavior

So, to make emacs (what else?) the default for MIME type text/plain

locate -r 'emacs.*\.desktop'
xdg-mime default emacs.desktop text/plain
if [[  ! -z "`which xdg-open`" ]]; then alias open='xdg-open '; fi

All done

touch $HOME/.bashrc-ran
debug ".bashrc done"