Aliases and helper functions for the shell

2020-07-03

This is a compilation of shell aliases and helper functions I found useful and use more or less regularly. Some of them are of my creation and some have been stolen and adapted over the years. It's not a complete list. Just the ones that I think might be useful to somebody else.

This comes from a toot from pamela@, and I thought to put it here to be more permanent.

I use zsh on my machines as interactive shell, but I guess this can be used with little to no modification on other shells. I also use tmux(1) heavily.

Basic aliases

First some basic aliases (comments in line):

# create a tmux split 82 columns wide, used to take a peek at man pages
alias tman='tmux split-window -h -l 82 man'

Update 2021-05-01: Reader Chang, Chu-Kuan sends me a variation of this last one that does not require you to have a free terminal to invoke it. It's basically the same but with a tmux(1) bind key. This should go in your .tmux.conf:

bind-key M command-prompt -I 'split-window -h -l 82 man '

And now, more aliases:

# I use kubernetes at work, so those save a lot of typing.
# I also use some custom subcommands, via kubectl plugins.  I might write about
# that ...
if command -v kubectl > /dev/null ; then
    alias k='kubectl'
    alias kg='kubectl get'
    alias kgdep='kubectl get deployment'
    alias kgsvc='kubectl get service'
    alias kging='kubectl get ingress'
    alias kgcm='kubectl get configmap'
    alias kgsec='kubectl get secret'
    alias kd='kubectl describe'
    alias ka='kubectl apply -f'
    alias krm='kubectl delete'
    alias kex='kubectl exec -i -t'
    alias kedep='kubectl edit deployment'
    alias kecm='kubectl edit configmap'
    alias ktopn='kubectl top node'
fi

# also for work, google cloud sdk stuff ...
if command -v gcloud > /dev/null ; then
    alias gcil='gcloud compute instances list'
    alias gcssh='TERM=screen-256color gcloud compute ssh'
    alias gcscp='gcloud compute scp'
    # those 2 are specially useful, to sync the context change
    # for Google cloud project and kubernetes cluster
    alias Sprod='kubectl config use-context prod; gcloud config configurations activate prod'
    alias Sstg='kubectl config use-context stg; gcloud config configurations activate default'
fi

# I always forget to use doas with pkg_* commands.  Also, set -Dsnap which
# never hurts
if command -v pkg_add > /dev/null; then
    for c in add delete check; do
        alias pkg_${c}="doas /usr/sbin/pkg_${c} -Dsnap"
    done
    alias pkg_info="/usr/sbin/pkg_info -Dsnap"
fi

Named directories

I also make some heavy use of named directories in zsh. This is probably not present on other shells.

The thing is that I can refer to common used folders by a short name, like ~se for $HOME/src/git.e1e0.net and things like that. And they work anywhere on the command line. Here some examples:

test -d $HOME/src && hash -d s=$HOME/src
test -d $HOME/src/git.e1e0.net && hash -d se=$HOME/src/git.e1e0.net
test -d /mnt/nas/fotos && hash -d f=/mnt/nas/fotos
...

Helper functions

The next bits are for interacting with my transmission server at home. I never remember the options and stuff, so this covers the basic operations:

# list torrents
alias trls='transmission-remote my.transmission.host --authenv -l'

# remove a torrent from the list (-d deletes the downloaded files too)
function trrm () {
    if [[ "$1" == "-d" ]]; then
        action="--remove-and-delete"
        torrent="$2"
    else
        action="--remove"
        torrent="$1"
    fi
    transmission-remote my.transmission.host --authenv -t $torrent $action
}

# clean all torrents from the queue
function trclean() {
    for i in $(transmission-remote my.transmission.host --authenv -l | awk '$2=="100%" {print $1}')
    do
        if [[ "$1" == "-d" ]]; then
            action="--remove-and-delete"
        else
            action="--remove"
        fi
        transmission-remote my.transmission.host --authenv -t $i $action
    done
}

For adding torrents I use a python script so I can put them more or less automatically in folders to organize them, but that's a bit more complicated.

Some temperature conversion helpers (not used every day, but nice to have):

# temperature conversion
function c2f() {
    F=$(printf "scale=2\n$1 *  1.80 + 32\n" | bc)
    printf "C: $1\nF: $F\n"
}

function f2c() {
    C=$(printf "scale=2\n($1 -32)/1.80\n" | bc)
    printf "F: $1\nC: $C\n"
}
# for everything else, use units(1)

This one is pretty useful, as my ISP changes my public IP regularly.

# What is my External IP
function myip() { printf "External IP: %s\n" $(curl -s -4 http://ifconfig.co/) ;}

Small random ones (commented in place):

# quick and dirty file backup.
function bak() {
    cp -v ${1}{,.bak}
}

# replace all spaces by underscore (only for zsh)
function mvsp() {
    autoload -U zmv
    zmv '* *' '$f:gs/ /_'
}

# Grep the history with 'h'
function h () {
    if command -v rg > /dev/null 2>&1
    then
        mycommand=rg
    else
        mycommand=grep
    fi

    history 0 | $mycommand $1
}

# weather forecast on the terminal.  Just fantastic.
function wf () {
    CITY=$1
    if [[ -z "$CITY" ]]; then
        CITY="MyCity"
    fi
    curl wttr.in/${CITY}
}

# function to copy main ssh keys to clipboard when needed.
function pubkey () {
    ssh-add -L |grep 'cardno:000000000000' |\
      xclip -f -selection clipboard
    echo "=> Public key copied to clipboard."
}

# Neat trick from https://github.com/lf94/peek-for-tmux/blob/master/README.md
# temporary tmux split (1/3 of the window) to look into some file
function peek() {
    tmux split-window -p 33 less $@ || exit;
}

This one I use quite a bit. It's my personal pastebin:

# poor man's pastebin service (and secure !)
function pb() {
    filename="$1"
    dest=""
    if [[ -z "$filename" ]]; then
        dest=$(tr -cd '[:alnum:]' < /dev/urandom |dd bs=1 count=8 2>/dev/null)
        ssh w1.e1e0.net "cat > /var/www/pastes/$dest"
    else
        dest=$(basename "$filename")
        scp -q "$filename" "w1.e1e0.net:/var/www/pastes/$dest"
    fi
    echo -n "https://e1e0.net/paste/$dest" |\
        xclip -f -selection clipboard
    echo ''
}

It can be used like echo foo | pb or pb myfile.txt and will produce a unique URL if no file name is provided.

And a shortcut and dispatcher for git. g executes git status -s and everything else is just passed to git as is.

function g() {
    if (( $# == 0 )); then
        git status -s
    else
        git "$@"
    fi
}

OpenBSD ports stuff.

And now the ports stuff. All this is probably overkill, but I use them all the time while working with ports.

As the comment at the top says this is totally stolen from other devs. I can't remember what's from who, I probably took bits and pieces from their public dot files and just adapted it to my needs.

Basically this is a dispatcher function p. It composes the name of the function to call. If it exists it's called, if not the _port-doas function is called. This is useful as I use PORTS_PRIVSEP=Yes so everything in ports belongs to the user _pbuild.

Some functions make use of external commands like danj@'s show-victims (this is actually a rewrite I did in Go, the original in Python) to look for consumers of a port, or juanfra@'s outdated-packages.py to query portroach. The latter is pretty useful for "port fishing". Remember folks, there are a lot of outdated ports without maintainer !

# ports stuff
# shamelessly stolen from Klemens Nanni (kn@), Daniel Jakots (danj@)
# and Solene Rapenne (solene@)

p() {
    [ $# -gt 0 ] || return
    if typeset -f \_port-"$1" > /dev/null; then
        _port-"$@"
    else
        _port-doas "$@"
    fi
}

function _port-search() {
    local pt="/usr/ports"

    [[ -z ${1} ]] && echo "Need a keyword to search for" && return
    [[ ! -d ${pt} ]] && echo "Cannot find ports tree" && return

    cd ${pt} && make search name=${1}
    cd -
}
function _port-s() { \_port-search "$@" }

function _port-sql() { sqlite3 /usr/local/share/sqlports }
function _port-pldc() { make port-lib-depends-check }
function _port-ldc() { make lib-depends-check }
function _port-pdf() {
    if command -v cdiff > /dev/null ; then
        diff -up pkg/PLIST.orig pkg/PLIST | cdiff
    else
        diff -up pkg/PLIST.orig pkg/PLIST | less
    fi
}
function _port-src() { cd `make show=WRKSRC` }
function _port-clean() { make clean=all }

function _port-diff()
{
    if [[ -d /usr/ports/.got/ ]]; then
        got diff > /usr/ports/mystuff/${PWD##*/}.diff
    else
        cvs diff > /usr/ports/mystuff/${PWD##*/}.diff
    fi
    if command -v cdiff > /dev/null ; then
        cdiff /usr/ports/mystuff/${PWD##*/}.diff
    else
        less /usr/ports/mystuff/${PWD##*/}.diff
    fi
}
function _port-df() { \_port-diff "$@" }

function _port-lessdiff() {
    if command -v cdiff > /dev/null ; then
        cdiff /usr/ports/mystuff/${PWD##*/}.diff
    else
        less /usr/ports/mystuff/${PWD##*/}.diff
    fi
}
function _port-ldf() { \_port-lessdiff "$@" }

function _port-pygrep() { rg $@ --type make --glob '!*mystuff*' --glob '!lost+found' /usr/ports/*/py-* }

function _port-f() { \_port-find "$@" }
function _port-find() { rg -i $@ /usr/local/share/sqlports.list }

function _port-grep() { rg $@ --type make --glob '!*mystuff*' --glob '!lost+found' /usr/ports }

function _port-update() {
    local current_dir=$(pwd)
    if [[ -d /usr/ports/.got ]]; then
        cd /var/git/ports.git/ && git fetch origin master:master
        cd /usr/ports && got update -b master
        cd "$current_dir"
    else
        cd /usr/ports && cvs -q up -Pd -A && cd "$current_dir"
    fi
}
function _port-up() { \_port-update "$@" }

function _port-lessmake() { less "/usr/ports/$1/Makefile" }
function _port-lmk() { \_port-lessmake "$@" }

function _port-doas() {
    command doas -u _pbuild "$@"
}

function _port-help() {
    # (k) returns only the keys from associative array.  Look zshexpn(1)
    printf "%s\n" "${(k)functions[@]}" | sort | grep "^_port-" | sed 's/_port-//'
}

function _port-ou() { \_port-outdated "$@" }
function _port-outdated() {
    if [ ! -x "$HOME/bin/outdated-packages.py" ]; then
        echo "Cannot find script" >&2 && return
    fi
    "$HOME/bin/outdated-packages.py" "$@"
}

function _port-sv() { \_port-showvictims "$@" }
function _port-showvictims() {
    if [ ! -x "$HOME/bin/port-showvictims" ]; then
        echo "Cannot find executable" >&2 && return
    fi
    "$HOME/bin/port-showvictims" "$@"
}

function _port-patch {
    local level=${2:-0}
    patch -E -C -p$level < $1 && patch -E -p$level < $1
    echo $?
}

alias py3='env FLAVOR=python3 '

function cvsdiff() {
    if command -v cdiff > /dev/null ; then
        cvs diff $@ | cdiff
    else
        cvs diff $@ | less
    fi
}

And that's basically it. I hope is useful for somebody.

Have any comments ? Send an email to the comments address.