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"
                fi

                if ! 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
}

03.07.2014 20:07 CC0 opensource software Source

Similar posts

Null Comment zu New shell gimmicks



Add Comment:
Aus welchem Land kommen Sie?
Land*:
Your comment will only displayed publicly after my approval! Fields marked with * are mandatory.
If you include an email address, it will be deleted automatically after one month. Nothing else will be stored.