# Rod's .bashrc file (Rod Moffitt rod@rod.info)
# $Id: bashrc 13240 2011-12-09 06:07:42Z rmoffitt $
# Copyright (C) Rod Moffitt + others
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# if not running interactively, don't do anything
[ -z "$PS1" ] && return
# source the system bashrc if one exists
if [ -e "/etc/bash.bashrc" ]; then
. /etc/bash.bashrc
fi
# automatic setting of $DISPLAY (if not set already)
# this works for linux - your mileage may vary...
function get_xserver
{
case $TERM in
xterm )
XSERVER=$(who am i | awk '{print $NF}' | tr -d ')''(' )
XSERVER=${XSERVER%%:*}
;;
aterm | rxvt)
# find some code that works here...
;;
esac
}
if [ -z ${DISPLAY:=""} ]; then
get_xserver
if [[ -z ${XSERVER} || ${XSERVER} == $(hostname) || ${XSERVER} == "unix" ]]; then
DISPLAY=":0.0" # display on local host
else
DISPLAY=${XSERVER}:0.0 # display on remote host
fi
fi
export DISPLAY
# some settings
ulimit -S -c 0 # don't want any coredumps
set -o notify
#set -o noclobber # to prevent direction deleting files
#set -o xtrace # useful for debuging
#set -o nounset # useful for debuging
# enable options
shopt -s cdspell
shopt -s checkhash
shopt -s checkwinsize
shopt -s sourcepath
shopt -s no_empty_cmd_completion # bash >= 2.04 only
shopt -s cmdhist
shopt -s histappend histreedit histverify
shopt -s extglob # necessary for programmable completion
# disable options
shopt -u mailwarn
unset MAILCHECK # disable shell warning of incoming mail
export TIMEFORMAT=$'\nreal %3R\tuser %3U\tsys %3S\tpcpu %P\n'
export HISTIGNORE="&:bg:fg:h"
export HISTSIZE=10000
export HISTTIMEFORMAT="%F %H:%M:%S "
export HOSTFILE=~/.hosts # put a list of remote hosts in ~/.hosts
# color definitions
red='\e[0;31m'
RED='\e[1;31m'
green='\e[0;32m'
GREEN='\e[1;32m'
blue='\e[0;34m'
BLUE='\e[1;34m'
cyan='\e[0;36m'
CYAN='\e[1;36m'
yellow='\e[0;33m'
YELLOW='\e[1;33m'
NC='\e[0m' # no color
function xtitle
{
echo -en "\033]0;$*\007"
}
# find a file with a pattern in name:
function ff { find . -type f -iname '*'$*'*' -ls ; }
# find a file with pattern $1 in name and execute $2 on it:
function fe { find . -type f -iname '*'$1'*' -exec "${2:-file}" {} \; ; }
# find pattern in a set of files and highlight them
function fstr
{
OPTIND=1
local case=""
local usage="fstr: find string in files.
Usage: fstr [-i] \"pattern\" [\"filename pattern\"] "
while getopts :it opt
do
case "$opt" in
i) case="-i " ;;
*) echo "$usage"; return;;
esac
done
shift $(( $OPTIND - 1 ))
if [ "$#" -lt 1 ]; then
echo "$usage"
return;
fi
local SMSO=$(tput smso)
local RMSO=$(tput rmso)
find . -type f -name "${2:-*}" -print0 | xargs -0 grep -sn ${case} "$1" 2>&- | \
sed "s/$1/${SMSO}\0${RMSO}/gI" | more
}
# cut last n lines in file, 10 by default
function cuttail
{
nlines=${2:-10}
sed -n -e :a -e "1,${nlines}!{P;N;D;};N;ba" $1
}
# crops off the end of stdin to the specified size when a +ve argument,
# otherwise crops off the specified size from the start of a stdin for a
# -ve argument, size is in bytes unless a sufix of k/K (kilobytes 1000),
# m/M (megabytes 1000000), g/H (gigabytes 1000000000) is found - Rod
function crop
{
local len=$1
local bs=1
case "$len" in
*k|*K|"* k"|"* K") bs=1000 ;;
*m|*M|"* m"|"* M") bs=1000000 ;;
*g|*G|"* g"|"* G") bs=1000000000 ;;
*) ;;
esac
len=$(echo $len | sed -e "s#[a-zA-Z]*##g")
if [ $len -le 0 ];
then
len=$(echo $len | sed -e "s#\-##g")
dd bs=$bs skip=$len 2> /dev/null
else
dd bs=$bs count=$len 2> /dev/null
fi
}
# crop a file without having to make an intermediate temp file - Rod
function filecrop
{
local TMPFILE=tmp.$$
cat "$1" | crop "$2" > $TMPFILE
mv -f $TMPFILE "$1"
}
# du will bork if presented with a very large number of files via the command
# line, fdu gets around this by using find to gather the list of files, the first
# parameter is the directory (. if omitted), any other parameters are passed to du
function fdu
{
local where=.
local opt=
if [ "$#" -ge 1 ]; then
where=$1
shift
if [ "$#" -ge 1 ]; then
opt=$*
fi
fi
find $where -type f -exec du $opt \{\} \;
}
# clean up source files by: 1) fromdos'ing 2) removing excess white-space
# 3) converting tabs to 3 space - Rod
function cleansrc
{
local fromdos=`which fromdos 2> /dev/null`
if [ -z "$fromdos" ]; then
echo "can't find fromdos"
else
for filename;
do
local TMPFILE=tmp.$$
$fromdos < "$filename" | sed -e "s/\s*$//g;s/\t/ /g" > $TMPFILE
mv -f $TMPFILE "$filename"
done
fi
}
# lowercase and change spaces and extraneous dots to underscores in filenames - Rod
# - put '-num' before the name to optionally remove leading '999_' numbers
# - put '-count' before the name to optionally prefix the files with an increasing index
function lowercase
{
local mv=`which mv 2> /dev/null`
if [ -z "$mv" ];
then
echo "can't find mv"
else
local nonum="";
local count="";
for filename;
do
case "$filename" in
"-num" ) nonum="yes";;
"-count" ) count=1;;
* )
if [ ! -e "$filename" ];
then
echo "lowercase: $filename doesn't exist"
else
local dir=$(dirname "$filename")
if [ $dir == "." ];
then
dir=""
else
dir="$dir/"
fi
local nf=$(basename "$filename" | tr A-Z a-z | \
tr '[:cntrl:]\\\177-\377,:;()\-\[\]!@#\$%\^\?\*~{}=]' ' ' | \
sed -e 's/"//g' | sed -e "s/'//g" | sed -e 's/`//g' | sed -e s#\and#g | \
sed -e 's/[[:space:]]/_/g;s/_\+/_/g;s/^_//;s/_$//;s/\_\./\./g;s/\.\_/\_/g')
local gotdots=$(echo $nf | grep "\.\." -)
while [ "$gotdots" != "" ];
do
nf=$(echo $nf | sed -e 's/\.\./\./g')
gotdots=$(echo $nf | grep "\.\." -)
done
if [ ! -d "$filename" ];
then
local last=$nf
gotdots=$(echo $nf | grep "\." -)
while [ "$gotdots" != "" ];
do
last=$nf
nf=$(echo $nf | sed -e 's/\./_/')
gotdots=$(echo $nf | grep "\." -)
done
nf=$last
else
nf=$(echo $nf | sed -e 's/\./_/g')
fi
if [ -n "$nonum" ];
then
nf=$(echo $nf | sed -e 's#^[0-9]*_##g')
fi
if [ -n "$count" ];
then
nf=$(printf "%03d_$nf" $count)
count=$(($count + 1))
fi
local newname="${dir}${nf}"
if [ "$filename" != "$newname" ];
then
$mv -i -- "$filename" "$newname"
echo "lowercase: $filename --> $newname"
else
echo "lowercase: $filename not changed"
fi
fi
;;
esac
done
fi
}
# rename files with random names with 32 character file names, preserving the
# file extension - Rod
function randrename
{
local mv=`which mv 2> /dev/null`
if [ -z "$mv" ];
then
echo "can't find mv"
else
for filename;
do
if [ ! -e "$filename" ];
then
echo "randrename: $filename doesn't exist"
else
local dir=$(dirname "$filename")
if [ $dir == "." ];
then
dir=""
else
dir="$dir/"
fi
local nf=$(basename "$filename")
local last=$nf
local gotdots=$(echo $nf | grep "\." -)
while [ "$gotdots" != "" ];
do
last=$nf
nf=$(echo $nf | sed -e 's/\./_/')
gotdots=$(echo $nf | grep "\." -)
done
last=$(echo $last | sed 's/[^\.]*//')
local randname=$(randpw 32 | tr A-Z a-z)
local newname="${dir}${randname}${last}"
if [ "$filename" != "$newname" ];
then
$mv -i -- "$filename" "$newname"
echo "randrename: $filename --> $newname"
else
echo "randrename: $filename not changed"
fi
fi
done
fi
}
# updates the link to a file - Rod
function relink
{
if [ "$#" -lt 2 ]
then
echo "usage: relink
{ ... }"
elif [ ! -d "$1" ]
then
echo "directory '$1' doesn't exist"
else
local dir=$1
shift
for filename;
do
local link=$(find $dir -name $filename)
if [ -n "$link" ]
then
ln -sf "$link"
echo "relink: linking $link"
else
echo "relink: failed to find $file"
fi
done
fi
}
# renames a file adding the resolution to the end - Rod
function renameres
{
local identify=`which identify 2> /dev/null`
local mv=`which mv 2> /dev/null`
if [ "$#" -lt 1 ]
then
echo "usage: renameres { ... }"
elif [ -z "$identify" ];
then
echo "can't find identify (apt-get install imagemagick)"
elif [ -z "$mv" ];
then
echo "can't find mv"
else
for filename;
do
if [ ! -e "$filename" ];
then
echo "renameres: $filename doesn't exist"
else
local res=$($identify -ping -format "%wx%h" "$filename")
if [ -z $res ]
then
echo failed to determine resolution of "$filename"
else
local filebase=${filename%.*}
local ext=$((${#filename}-${#filebase}))
ext=${filename: -$ext}
res=$(echo "$filebase" | sed "s/$/_${res}$ext/")
$mv -i -- "$filename" "$res"
echo "renameres: $filename --> $res"
fi
fi
done
fi
}
# finds a free loop device and uses it - Rod
function flosetup
{
if [ "$#" -lt 1 ]; then
echo "missing file"
return -1
fi
local losetup=`which losetup 2> /dev/null`
local lobase='/dev/loop';
local loopidx=0
local lofile=$1
if [ -z "$losetup" ];
then
echo "can't find losetup"
return -1
fi
if [ ! -f "$lofile" ];
then
echo "invalid file"
return -1
fi
while true
do
local lodev=$lobase/$loopidx;
if [ ! -b $lodev ];
then
echo "failed to find free loop device"
return -1
fi
$losetup $lodev $lofile 2> /dev/null
if [ $? -eq 0 ];
then
echo "$lodev"
return 0
fi
loopidx=$((loopidx+1))
done
}
# detaches a loop device based on the mount - Rod
function closetup
{
if [ "$#" -lt 1 ]
then
echo "missing mount"
return -1
fi
local losetup=`which losetup 2> /dev/null`
local lomount=$1
if [ -z "$losetup" ];
then
echo "can't find losetup"
return -1
fi
loopdev=`$losetup -a 2> /dev/null | grep $lomount | sed s/:.*//g`
if [ -n "$loopdev" ];
then
$losetup -d $loopdev 2> /dev/null
else
return -1
fi
}
# simple dump of alphanumeric characters, useful for mouse picking
# passwords when it isn't safe to use the keyboard - Rod
function chars
{
letters='abcdefghijklmnopqrstuvwxyz'
letters=$letters$(echo $letters | tr 'a-z' 'A-Z')
echo ${letters}0123456789
}
# find all files under the current directory which grep the specified id3
# information, example 'id3find Trainspotting *' - Rod
function id3find
{
local string=$1
shift
local tempfile=/tmp/.id3find.$$
for file in $@
do
id3info $file > $tempfile 2> /dev/null
test=$(grep -i "$string" $tempfile)
if [ -n "$test" ]; then echo $file; fi
done
rm -f $tempfile
}
# swap 2 filenames around
function swap
{
local TMPFILE=tmp.$$
mv "$1" $TMPFILE
mv "$2" "$1"
mv $TMPFILE "$2"
}
function my_ps { ps $@ -u $USER -o pid,%cpu,%mem,bsdtime,command ; }
function pp { my_ps f | awk '!/awk/ && $0~var' var=${1:-".*"} ; }
# get current host related info
function ii
{
echo -e "\n${RED}You are logged on ${YELLOW}$HOSTNAME$NC as ${GREEN}$USER"
echo -e "\n${RED}Additionnal information:$NC "; uname -a
echo -e "\n${RED}Users logged on:$NC "; w -h
echo -e "\n${RED}Current date:$NC "; date
echo -e "\n${RED}Machine stats:$NC "; uptime
echo -e "\n${RED}Memory stats:$NC "; free
echo
}
# repeat n times command
function repeat
{
local i max
max=$1
shift
for ((i=1; i <= max ; i++));
do
eval "$@"
done
}
# ask for confirmation
function ask
{
echo -n "$@" '[y/n] '
read ans
case "$ans" in
y*|Y*) return 0 ;;
*) return 1 ;;
esac
}
# cool little function to prevent 'rm * .txt' when you meant 'rm *.txt',
# tcsh beats bash in only this feature, now bash has it as well! - Rod
function rmstar
{
set +f # re-enable globbing
local oldargs="$@"
# search for a '*'
until [ -z "$1" ]
do
if [ "$1" == "*" ]
then
ask "Do you really want to delete all files?"
if [ "$?" -eq 1 ]
then
return
fi
fi
shift
done
local rm=`which rm 2> /dev/null`
$rm $oldargs
}
# need to temporarily disable globbing to allow re-running of 'rm' with the
# string asis, the only down side is that if this alis is run in the background
# then set +f won't be set until the command completes - Rod
alias rm="IFS='^'; set -f; rmstar"
# clean up a path, removing excess forward slashes - Rod
function cleanpath
{
echo $1 | sed -e "s#//*#/#g" -e 's#/$##g' -e 's#/:#:#g'
}
# nice routine to manage paths, first argument is the command:
# to either "insert" it at the beginning, "append" it to the end,
# "remove" the entry, all operating with the second argumemt, or
# any other command string to show the current path - Rod
function path
{
dir=$(cleanpath "$2")
PATH=$(cleanpath "$PATH" | sed -e "s/^/:/" -e "s/$/:/" \
-e "s#:$dir:#:#g" -e "s/^://" -e "s/:$//")
case "$1" in
i* ) PATH=$2:$PATH ;;
a* ) PATH=$PATH:$2 ;;
r* ) ;;
* ) echo -e ${PATH//:/\\n} ;;
esac
}
# echo text taken from stdin using the color specified as the argument
# which must be listed under 'color definitions' above - Rod
function color
{
eval col=\$$1
echo -ne $col
cat /dev/stdin
echo -ne "$NC"
}
# outputs data in colon-separated hex format - Rod
function bin2hex
{
local hexdump=`which hexdump 2> /dev/null`
if [ -z "$hexdump" ];
then
echo "can't find hexdump"
else
$hexdump -ve '1/1 "%02x:"' | sed s#:\$#\\n#
fi
}
# outputs data in hex format, optionally limits length to
# specified number of hex chars - Rod
function bin2nhex
{
local hexdump=`which hexdump 2> /dev/null`
if [ -z "$hexdump" ];
then
echo "can't find hexdump"
else
local data=$($hexdump -ve '1/1 "%02x"' | sed s#\$#\\n#)
if [ "$#" -eq 1 ]; then
data=$(echo $data | head -c $1)
fi
echo $data
fi
}
# outputs data in C friendly char array hex format - Rod
function bin2chex
{
local hexdump=`which hexdump 2> /dev/null`
if [ -z "$hexdump" ];
then
echo "can't find hexdump"
else
bin2hex | sed -e "s#^#const unsigned char myarray\[\] = { 0x#;s#:#, 0x#g;s#\$# };#"
fi
}
# for every file under a directory create a single line with
# an MD5 hash and the file name converted so it can be
# sorted and easily compared no matter what system it is on
function md5dir
{
local md5deep=`which md5deep 2> /dev/null`
if [ -z "$md5deep" ]
then
echo "can't find md5deep"
elif [ $# -ne 1 ];
then
echo "usage: md5dir "
else
$md5deep -lr ${1} | sed s#${1}## | tr -d [:punct:][:blank:] | sort -df
fi
}
# uses md5dir to provide a single hash of a directory
function md5dirsum
{
local md5deep=`which md5deep 2> /dev/null`
if [ -z "$md5deep" ]
then
echo "can't find md5deep"
elif [ $# -ne 1 ];
then
echo "usage: md5dirsum "
else
md5dir "${1}" | $md5deep | sed "s#-#${1}#"
fi
}
# get a random number, between 0 and the argument-1 - Rod
function rand
{
local base64=`which base64 2> /dev/null`
if [ $# -lt 1 ];
then
echo "usage: rand "
elif [ ! -r "/dev/urandom" ] || [ -z "$base64" ];
then
echo "can't read /dev/urandom and/or find base64"
elif [ $1 -gt 0 ];
then
# get some real entropy
RANDOM=$(head -c 20 /dev/urandom | $base64 \
| sed -e "s#[^0-9]*##g" | tail -c 5)
# because of integer rounding larger numbers cause overflow on results
echo $(($RANDOM/(32768/$1)))
else
echo "invalid ceiling value"
fi
}
# select randomly from a argument - Rod
function randlist
{
if [ $# -gt 0 ];
then
local index=$(rand $#)
shift $index
echo $1
fi
}
# outputs a specific amount of random data - Rod
function randdata
{
if [ $# -lt 1 ];
then
echo "how much random data?"
elif [ $1 -gt 0 ];
then
head -c $1 /dev/urandom
else
echo "invalid length"
fi
}
# removes repeating characters from a string - Rod
function charuniq
{
local i
local str=$1
local len=$(echo -n $str | wc -c)
for ((i=1; i < $(($len/2+2)); i++));
do
str=$(echo "$str" | sed 's/\(.\)\1/\1/g')
done
echo "$str"
}
# outputs a random password by piping /dev/urandom into base64, since not all
# password based systems allow non-alphanumerics they are filtered out, takes
# a single parameter which is the number of characters - Rod
function randpw
{
local base64=`which base64 2> /dev/null`
if [ $# -lt 1 ];
then
echo "what length?"
elif [ -z "$base64" ];
then
echo "can't find base64"
elif [ $1 -gt 0 ];
then
local testlen=0
local outlen=$1
local pw=""
while [ $testlen -lt $outlen ];
do
local in=$(head -c $((outlen*5/6+1)) /dev/urandom | $base64)
pw=$(echo "$pw$in" | tr -cd 'A-Za-z0-9')
pw=$(charuniq "$pw")
testlen=$(echo -n $pw | wc -c)
done
pw=$(echo "$pw" | head -c $outlen)
echo "$pw"
else
echo "invalid length"
fi
}
# generate a random 16 bit integer, good for selecting random ports - Rod
function randport
{
val=$(randdata 32 | bin2nhex 4)
echo $((0x$val))
}
# randomly moves out files to specified directory from current directory
# until specified size is met - Rod
function randpurge
{
if [ "$#" -lt 2 ]; then
echo "randpurge: "
return;
fi
local mv=`which mv 2> /dev/null`
if [ -n "$mv" ];
then
local len=$1
local destdir=$2
local bs=1
case "$len" in
*k|*K|"* k"|"* K") bs=1000 ;;
*m|*M|"* m"|"* M") bs=1000000 ;;
*g|*G|"* g"|"* G") bs=1000000000 ;;
*) ;;
esac
bslen=$(echo $len | sed -e "s#[a-zA-Z]*##g")
size=$(du --block-size=$bs -s | sed -e "s#\.##g")
if [ $bslen -le $size ];
then
files=$(find . | grep -v ^\.$)
file2mv=$(randlist $files)
if [ -n "$file2mv" ];
then
echo "moving $file2mv to $destdir"
$mv -i "$file2mv" "$destdir"
randpurge "$len" "$destdir"
fi
fi
fi
}
# run a command for a specified time (value is any time value supported by
# sleep) - Rod
function runfor
{
if [ "$#" -lt 2 ]; then
echo "runfor: