Common functions and aliases that I can share among all my computers.
This file is written to $HOME/.bash.all.rc
and should be called
from .bashrc
and/or .zshrc
, via:
if [ -f "$HOME/.sh-funcs.sh" ]; then
source "$HOME/.sh-funcs.sh"
fi
According to this article:
- For bash, put stuff in
~/.bashrc
, and make~/.profile
source it.
- For zsh, put stuff in ~/.zshrc
, which is always executed.
Machine-specific gunk goes in the standard .bashrc
and ~/.zshrc
files,
and global variables are stored in .profile
and .zsh_profile
.
The following are the tangled settings. Type: C-c C-v t
to create the script file.
Another wrapper around emacsclient
but this is a blocking
approach suitable for being set to the EDITOR
variable.
alias e='emacsclient -q -a emacs'
It is unclear whether e
is a good version for the EDITOR
variable. According to the info docs, we should do something like:
EDITOR="emacsclient"
My favorite diff tool is the ediff
tool in Emacs, and little
function (taken from this blog post) allows me to use it from the
command line.
function ediff() {
if [ -z "$2" ]
then
echo "USAGE: ediff <FILE 1> <FILE 2>"
else
# The --eval flag takes lisp code and evaluates it with EMACS
emacsclient -c --eval "(ediff-files \"$1\" \"$2\")"
fi
}
Using the GNU versions of ls
, which can be installed by Homebrew
or Ports, via: port install coreutils
if which gls >/dev/null 2>&1
then
alias ls="gls --color"
alias ll="gls --color -olhA"
else
alias ls="ls --color"
alias ll="ls --color -olhA"
fi
The interface to find
, while powerful, if quite obnoxious. Here
is a few wrapper functions.
Wrapper around ‘find’ that excludes some useless directories, like
classes
and .git
that ignores case, and does an or around
every file name.
The first parameter can be a source directory to look for the file(s), or you can do something like ‘src/../some-file.txt’ to look in the ‘src’ directory for the files.
function findit {
START_PATH='.'
FILES="$*"
# If we have a phrase src/../nav.handlebars, then we want to look
# in the 'src' directory for the filename given:
if echo "$1" | grep '\.\.' >/dev/null
then
set $(echo "$1" | sed 's/\/*\.\.\/*/ /');
fi
# If the first option is a directory, then look in that path, otherwise,
# start searching from the current directory.
if [ -d "$1" -a -n "$2" ]
then
START_PATH=$1
shift
FILES="$*"
fi
# Ignore the classes and .git directories, as well as look for every
# file name given.
find $START_PATH \
-not \( -path '*classes*' -or -path '*node_modules*' -or -path '.git*' \) \
-and -iname $(perl -e 'print join " -o -iname ", @ARGV' $FILES)
}
alias f='noglob findit'
Wrapper around ‘find’ that returns only a single file. Helpful for calls to an editor when you are pretty sure of the name of the file.
function sf {
noglob findit *$1* | head -1
}
Combines my ‘f’ and ‘e’ functions to easily edit a file in the local directory tree solely by the file name.
function ef {
e $(f $*)
}
According to this document, we can ignore the man in the middle
attacks with a couple of parameters. Why is this good? Well, I have
transient hosts that often get rebuilt with the same IP address, and
editing the .ssh/known_hosts
file is pretty obnoxious.
alias sshf='ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
Granted, I like this sed
command for quickly dispatching the
offending line from the file:
sed -i 3d ~/.ssh/known_hosts
For some odd reason, I find I often need to copy the files from a checked out
branch from a Git repository, to a remote server, but without the entire repository.
By using tar
’s exclude
option, we can do a pipe to ssh
.
Parameters:
$1
- The directory to copy
$2
- The remote server (which can include any options to ssh
)
function scp-git {
DIR=$1
shift
tar -cjf - --exclude .git $DIR | ssh $* 'tar -xjvf -'
}
I like Dash for pulling up quick technical information, and while I normally use it from Emacs, the following alias is nice from the terminal:
function dash {
"open dash://$@"
}
Can we title the terminal window? Note, don’t call this function
title
or bad things will happen.
function xtitle {
# Old Style? echo -n -e "\033]0;$*\007";;
case "$1" in
-t) shift; echo "\e]1;$*\a";;
-w) shift; echo "\e]2;$*\a";;
-b) shift; echo "\e]0;$*\a";;
*) echo "\e]0;$*\a";;
esac
}
Opens a tab in the `Terminal` program and start something running in it.
function xtab() {
TITLE="$1"
if [[ $1 = "-t" ]]
then
TITLE="$2"
shift
shift
fi
HISTFILE=$HOME/.zsh_histories/$(echo $TITLE | sed 's/ /_/g')
osascript <<EOF
tell application "System Events"
tell process "Terminal" to keystroke "t" using command down
end
tell application "Terminal"
activate
set custom title of first window to "$TITLE"
-- do script "echo '\e]1;$TITLE\a'" in window 1
do script with command "xtitle $TITLE; HISTFILE=$HISTFILE; clear; $*" in window 1
end tell
EOF
}
Created tag listing and other shell scripts to deal with embedded
org-mode
tags. Each of these take a list of files, so these are
some functions that give the files in the default locations.
export NOTEPATH="$HOME/Notes"
for FILE in $HOME/Technical $HOME/Personal
do
if [ -e "$FILE" ]; then
NOTEPATH="$FILE:$NOTEPATH"
fi
done
Based on the $NOTEPATH
variable, we can get all possible notes.
function all-note-dirs {
echo $NOTEPATH | sed 's/:/ /g'
}
function all-notes {
# echo find `all-note-dirs` -name '*.org'
find -L `all-note-dirs` -name '*.org'
}
And then we can grep for text in just our notes:
function ngrep {
egrep -r --max-count=1 --context=3 --include='*.org' --ignore-case \
--no-messages --word-regexp $* $(all-note-dirs)
}
Notable grep
options include:
- –max-count=1 to only display the first match from file
- –context=3 for extra lines around the match.
- –include=*.org To only display org-mode files
- –no-messages to get rid of errors
- –word-regexp to match whole words
- –ignore-case to ignore case distinctions
I can put this at the end of a long running command and have it tell me when it is complete. The “name” of the command is given as an optional parameter, which is spoken when it completes.
Options:
- -c The name of the command
- -b The name of the audio file to use in
/System/Library/Sounds
- -m The message. Don’t use this as a message including whether the command successfully completed or not is generated.
function beep {
# We first need to capture the status of the previous command
ERROR=$?
COMMAND="The command"
unset MESSAGE
# Default value for the audio depends on the success or failure
# of the previous command... and do we have Failure wave file.
if [ $ERROR -eq 0 ]
then
AUDIO=/System/Library/Sounds/Ping.aiff
else
AUDIO=~/.sh-funcs-error.wav
if [ ! -f "$AUDIO" ]
then
AUDIO=/System/Library/Sounds/Glass.aiff
fi
fi
while getopts "b:c:m:" o $*
do
case "$o" in
b) AUDIO=/System/Library/Sounds/$OPTARG.aiff;;
c) COMMAND="$OPTARG";;
m) MESSAGE="$OPTARG";;
[?]) print >&2 "Usage: $0 [-b audio] [-m message] [-c] command-name"
exit 1;;
esac
done
shift `expr $OPTIND - 1`
# I would like the -c argument to be truly optional, so that if words
# are just given, they are automatically assumed to have a -c in front.
if [ $# -gt 0 ]
then
COMMAND="$@"
fi
if [ -z "$MESSAGE" ]
then
if [ $ERROR -eq 0 ]
then
MESSAGE="$COMMAND has completed."
else
MESSAGE="$COMMAND has failed."
fi
fi
echo $MESSAGE
afplay $AUDIO
say $MESSAGE
if type terminal-notifier >/dev/null
then
terminal-notifier -message "$MESSAGE" -title "Process Complete"
fi
# In case we are still using && on the command line, we need to
# pass on the failure... and since we really can't assign $?
if [ $ERROR -ne 0 ]
then
/bin/ls /no-file 2>/dev/null # Make next process know previous failed
fi
}
If you want to gather data from the output, but starting with a
particular line, and ending with another, use clip
. For instance:
nmap -A 192.168.0.1 | clip 'PORT ' 'Service detection performed'
Will show just the “good” stuff from the nmap
command.
Function takes three arguments:
- The text (regular expression, actually) to use to begin printing
- The text to use to end printing (isn’t actually printed… should it?)
- Optional text inserted at the beginning of each line.
function clip {
FIRST=$1
ENDING=$2
PADDING=${3:-""}
perl -ne "\$s=1 if (/$FIRST/); \$s=0 if (/$ENDING/); print \"$PADDING\$_\" if (\$s==1);"
}
From this blog entry, comes details how to install the
source-highlight
program on the Mac in order to see various code
highlighted in pretty colors.
LESSPIPE=`which src-hilite-lesspipe.sh`
export LESSOPEN="| ${LESSPIPE} %s"
export LESS='-R'
Complete expected git (and others) commands by pressing the tab key for Bash.
if [ -n "$ON_A_MAC" ] && [ -f `brew --prefix`/etc/bash_completion ]
then
. `brew --prefix`/etc/bash_completion
fi
These alias remove trailing whitespace and lines containing nothing by spaces/tabs.
alias pre-commit='git status --porcelain | egrep '\''^[MA]'\'' | cut -d '\'' '\'' -f 3 | xargs perl -pi -e '\''s/\t/ /g; s/[\t ]+$//'\'''
alias pre-add='git status --porcelain | grep "^ M" | cut -d" " -f3 | xargs git add'
alias white='xargs perl -pi -e '\''s/\t/ /g; s/[\t ]+$//'\'''
Allows me to pull new information from the remote branch, but not loose anything.
function pull {
git stash
git pull
git stash pop
}
The following are shortcuts to some git commands that I use all the time. Most people prefix them with a ‘g’ character to keep them unique.
alias gst='git status'
alias gstatus='git status'
alias gd='git diff'
alias gdc='git diff --cached'
alias gaa='git add --update :/' # Use full 'git add' if haven't already added it
alias gamend='git commit --amend --no-edit'
alias gstash='git stash'
alias gpop='git stash pop'
alias gshow='git stash show -p stash@{0}'
alias gf='git status --porcelain | cut -c4-'
alias gf-new='git status --porcelain | grep "^??" | cut -c4-'
alias gf-changed='git status --porcelain | grep "^ M" | cut -c4-'
This script allows us to leave bookmarks to “popular” directories, to jump directly there with a single name.
- s bookmarkname - saves the curr dir as bookmarkname
- g bookmarkname - jumps to the that bookmark
- g b[TAB] - tab completion is available
- p bookmarkname - prints the bookmark
- p b[TAB] - tab completion is available
- d bookmarkname - deletes the bookmark
- d [TAB] - tab completion is available
- l - list all bookmarks
# The following may already be aliases...
unalias l >/dev/null 2>&1
unalias g >/dev/null 2>&1
unalias d >/dev/null 2>&1
if [ -e ~/.bash.d/bashmarks.sh ]
then
source ~/.bash.d/bashmarks.sh
fi