New shell gimmicks
So, I decided to streamline my shell config the other day. The very first I did, was to write an awk replacement in perl. Sounds a little senceless, but sometimes I need some more power inside an awk command and sometimes I just want to save typing. This is how it looks like, when used:
# awk version: ps | grep sleep | grep -v grep | awk '{print $1}' | xargs kill # pwk version: ps | grep sleep | grep -v grep | pwk 1 | xargs kill
This is the simple variant, which just saves typing, pretty handy. The other variant is more perlish and at first looks like the original awk syntax. Hover, you can add almost any kind of perl code to it:
ps | pwk 'if($5 =~ /^python$/) { $t=`fetch -o - "http://$8/"`; if($t =~ /<title>(.+?)<\/title/) { print "$8: $1"} }'
Here's the shell function, just put it into your .bashrc:
pwk () { if test -z "$*"; then echo "Perl awk. Usage:" echo "Perlish: pawk [-F/regex/] [-Mmodule] <perl code>" echo " Simple: pawk <1,2,n | 1..n>" echo "Perlish helpers:" echo " p() - print field[s], eg: p(\$1,\$4,\$7)" echo " d() - dump variables, without param, dump all" echo " e() - exec code on all fields, eg: e('s/foo/bar/')" echo echo "Default loaded modules: Data::Dumper, IO::All" echo "Enable \$PWKDEBUG for debugging" echo "Simple mode has no helpers or anything else" else # determin pwk mode if echo "$*" | egrep '^[0-9,\.]*$' > /dev/null 2>&1; then # simple mode code=`echo "$*" | perl -pe 's/([0-9]+?)/\$x=\$1-1;\$x/ge'` perl -lane "print join(' ', @F[$code]);" else # perl mode # prepare some handy subs uselib="use lib qw(.);" subprint="sub p{print \"@_\";};" subsed='sub e{$r=shift; foreach (@F) { eval $r; }};' subdump='sub d {$x=shift||{_=>$_,S=>\@F}; print Dumper($x);};' begin="; BEGIN { $uselib $stdsplit $subprint $subdump $subsed}; "# extract the code and eventual perl parameters, if any code="" args="" last="" for arg in "$@"; do args="$args $last" last="$arg" done code=$last # fix perl -F /reg/ bug, complains about file /reg/ not found, # so remove the space after -F args=`echo "$args" | sed -e 's/-F /-F/' -e 's/-M /-M/'` # convert $1..n to $F[0..n] code=`echo "$code" | perl -pe 's/\\\$([0-9]+?)/\$x=\$1-1;"\\\$F[\$x]"/ge'` # rumble defaultmodules="-MData::Dumper" if perl -MIO::All -e0 > /dev/null 2>&1; then defaultmodules="$defaultmodules -MIO::All" fi if test -n "$PWKDEBUG"; then set -x fi perl $defaultmodules $args -lane "$code$begin" if test -n "$PWKDEBUG"; then set +x fi fi fi
}
Another new shell function is extr, which unpacks any kind of archive. In contrast to its sisters out there (there are a couple of generic unpack shell funcs to be found on the net), it takes much more care about what it does. Error checking, you know. And it looks inside the archive to check if it extracts into its own directory, which is not always the case and very annoying. In such instances it generates a directoryname from the archivename and extracts it to there. Usage is simple: extr archivefile
. Here's the function:
extr () { act() { echo "$@" "$@" } n2dir() { tarball="$1" suffix="$2" dir=`echo "$tarball" | perl -pne "s/.$suffix//i"` dir=`basename "$dir"` echo "$dir" } tarball="$1" if test -n "$tarball"; then if test -e "$tarball"; then if echo "$tarball" | grep -Ei '(.tar|.jar|.tgz|.tar.gz|.tar.Z|.tar.bz2|tbz)$' > /dev/null 2>&1; then # tarball if echo "$tarball" | grep -E '.(tar|jar)$' > /dev/null 2>&1; then # plain old tarball extr="" elif echo "$tarball" | grep -E '(bz2|tbz)$' > /dev/null 2>&1; then extr="j" elif echo "$tarball" | grep -E 'Z$' > /dev/null 2>&1; then extr="Z" else extr="z" fiif ! tar ${extr}tf "$tarball" | cut -d/ -f1 | sort -u | wc -l | egrep ' 1$' > /dev/null 2>&1; then # does not extract into own directory dir=`n2dir "$tarball" "(tar.gz|tgz|tar.bz2|tbz|tar|jar|tar.z)"` mkdir -p $dir extr="-C $dir -${extr}" fi act tar ${extr}vxf $tarball elif echo $tarball | grep -Ei '.zip$' > /dev/null 2>&1; then # zip file if unzip -l "$tarball" | grep [0-9] | awk '{print $4}' | cut -d/ -f1 | sort -u \ | wc -l | egrep ' 1$' /dev/null 2>&1; then # does not extract into own directory dir=`n2dir "$tarball" zip` act mkdir -p $dir opt="-d $dir" fi act unzip ${opt} $tarball elif echo "$tarball" | grep -Ei '.rar$' > /dev/null 2>&1; then if ! unrar vt "$tarball" | tail -5 | grep '.D...' > /dev/null 2>&1; then # does not extract into own directory dir=`n2dir "$tarball" rar` act mkdir -p "$dir" (cd "$dir"; act unrar x -e $tarball) else act unrar x $tarball fi elif echo "$tarball" | grep -Ei '.gz$' > /dev/null 2>&1; then # pure gzip file act gunzip "$tarball" else : fi else echo "$tarball does not exist!" fi else echo "Usage: untar <tarball>" fi
}
And finally an updated version of my h function, which can be used for dns resolving. Usage is pretty simple:
% h theoatmeal.com ; dig +nocmd +noall +answer theoatmeal.com theoatmeal.com. 346 IN A 208.70.160.53% h 208.70.160.53 ; dig -x 208.70.160.53 +short oatvip.gpdatacenter.com.
% h theoatmeal.com mx ; dig +nocmd +noall +answer theoatmeal.com mx theoatmeal.com. 1800 IN MX 5 eforwardct2.name-services.com. theoatmeal.com. 1800 IN MX 5 eforwardct3.name-services.com. theoatmeal.com. 1800 IN MX 5 eforwardct.name-services.com.
It uses dig to do the work, or host if dig cannot be found. The source:
h () { if type dig > /dev/null 2>&1; then args="$*" opt="+nocmd +noall +answer" rev="" if echo "$args" | egrep '^[0-9\.:]*$' > /dev/null 2>&1; then # ip address cmd="dig -x $* +short" else # hostname cmd="dig +nocmd +noall +answer $*" fi echo "; $cmd" $cmd else # no dig installed, use host instead host="$1" type="a" debug="" cmd="host $debug" if test -z "$host"; then echo "Usage: h <host> [<querytype>]" return else if test -n "$2"; then type=$2 fi if test -n "$debug"; then set -x fi case $type in ls) $cmd -l $host ;; any) cmd=`echo $cmd | sed 's/\-d//'` $cmd -d -t any $host | grep -v ^\; | grep -v "^rcode =" ;; mx|a|ns|soa|cname|ptr) $cmd -t $type $host ;; *) echo "*** unsupported query type: $type!" echo "*** allowed: mx, a, ns, any, *, soa, cname, ptr" continue ;; esac if test -n "$debug"; then set +x fi fi fi }