#!/bin/bash ## hack to workaround Fedora/Red Hat bug 878428 #shellcheck disable=SC1091 test -f /usr/share/git-core/contrib/completion/git-prompt.sh \ && . /usr/share/git-core/contrib/completion/git-prompt.sh ####################################################### ### things to do BEFORE host/user-specific settings ### ####################################################### ### .... ### ### SUBZ ### ### '''' ### smv() { # # scp but rm the source # local src=$1 local dst=$2 test $# -eq 2 || { echo "i can only 2 argz!" >&2 return 2 } scp "$src" "$dst" && rm "$src" } smvr() { # # smv but recursive # local src=$1 local dst=$2 test $# -eq 2 || { echo "i can only 2 argz!" >&2 return 2 } scp -r "$src" "$dst" && rm -r "$src" } bb() { # # Ring the bell # local stime=${1:-0} test "$stime" == 0 || echo -e "sleeping for $BASHUM_COLOR_LGREEN$stime$BASHUM_COLOR_NORMAL" sleep "$stime" printf '\a' } nn() { # # Ring the bell and send notification $1 after $2 time # local msg=${1:-this is done} local stime=$2 bb "$stime" echo -e "hey, $BASHUM_COLOR_LRED$msg$BASHUM_COLOR_NORMAL" notify-send -a 'nn()' "hey, $msg" } pp() { # # Ring the bell and send notification $1 and pause # local msg=${1:-this is done} bb echo -e "hey, \033[1;31m$msg\033[1;0m!" notify-send -a 'pp()' "hey, $msg" read -r junk -p "Press Enter to continue" } lrep() { # # Print each line on STDIN $1 times # local rep=${1:-1}; shift local line local n while read -r line; do n=$rep while test "$n" -gt 0; do echo "$line" ((n--)) done done } prep() { # # Print STDIN $1 times # local rep=${1:-1}; shift local data data=$(cat) n=$rep while test "$n" -gt 0; do echo "$data" echo ((n--)) done } dt() { # # Open $1 new terminals # __bashum_run_n "${1:-1}" urxvt } dT() { # # Open $1 new alterminals # __bashum_run_n "${1:-1}" xfce4-terminal } hr() { # # Make horizontal ruler # local i local line for i in $(seq 1 "$COLUMNS"); do case $((i%10)) in 0) line+='#' ;; *) line+='-' ;; esac done echo "$line" echo "$line" echo "$line" } __bashum_run_n() { # # Run $2.. in background $1 times # local n=${1:-1}; shift while test "$n" -gt 0; do "$@" & ((n--)) done } twice() { # # Run $@ two times # "$@" "$@" } ckyaml() { # # Check if YAML file $1 is loadable # local yfile=$1 test -n "$yfile" || { echo "usage: ckyaml FILE.yaml"; return 2; } python -c 'import yaml; import sys; print(yaml.load(sys.stdin)["this"])' <"$yfile" } git() { # # /usr/bin/git wrapper just to disable dangerous commands # # In particular, `git-am` is a a close typo of my favorite # aliases `ap` (`git-add --patch`) and `cm` (`git-commit`) # but it's dangerous to call by accident as it destroys # workdir changes. # if grep -Fwqse "$1" "$GIT_DISABLED_COMMANDS"; then echo "You don't want this." >&2 return 1 else command git "$@" fi } grepcl() { # # Grep in common chat log files # # The order is from older apps to newer as I was moving towards # weechat. # grep "$@" -R \ "$HOME/.config/xchat2/xchatlogs" \ "$HOME/.config/xchat2/scrollback" \ "$HOME/.config/hexchat/logs" \ "$HOME/.config/hexchat/scrollback" \ "$HOME/.local/share/weechat/logs.old" \ "$HOME/.local/share/weechat/logs" } grepfx() { # # Grep recursively for technical debt # # '[F]' hack to avoid matching self # grep --color -n \ --exclude-dir 'utils' \ --exclude-dir '.git' \ -o '#[F]IXME:.*' -R "$@" } grepr() { # # Grep recursively, keeping numbers and ignoring common dirs # # Number one tool for refactoring! # local p=$1; shift grep --color -n --exclude-dir=".git" -e "$p" -R "$@" } grepr1() { # # Like grepr() but only list matching items in this directory # # Ie. list only files in current directory or names of subdirectories # where matches were found "somewhere". # grepr "$@" -l | cut -d/ -f1 | uniq } greph() { # # Grep through bash history # history | sed 's/^ *//; s/ / /' | cut -d' ' -f2- | grep "$@" } gitcd() { # # Deep in git repo, cd to the git root # cd "$(git rev-parse --show-toplevel)" || return 1 } clsz() { # # Clear screen and move the prompt to bottom # tput clear; tput cup "$(tput lines)" 0 } bcdiff() { # # Call bcompare only if objects actually differ # test $# -eq 2 && diff "$@" >/dev/null && return bcompare "$@" & } strip_colors() { # # Strip color codes from stdin # # Stolen from http://unix.stackexchange.com/a/4533/9365 # sed -r 's/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g' } vims() { # # List Vim .swp files in a nice table # # **Note:** For this ro work, you need to set up Vim to # use same swap directory as assigned below. this can # be achieved by addoing section such as this to your # .vimrc: # # if isdirectory($HOME . '/.local/share/vim') == 0 # :silent !mkdir -p ~/.vim/swap >/dev/null 2>&1 # endif # set directory=./.vim-swap// # set directory+=~/.local/share/vim/swap// # set directory+=~/tmp// # set directory+=. # # Call this after crash or poweroff to remind yourself what # files you were editing before fact. Example: # # 2015-07-10 06:10:48.603953758 +0200 ~/TODO.todo # # This should make it easier to recover after a little # disaster. # local swap="$HOME/.local/share/vim/swap" #shellcheck disable=SC1117 find "$swap" -type f -print0 \ | xargs -0 -r stat -c "%y %n" \ | sed " s| $swap/| | s|%|/|g s|.swp$|| s| $HOME| ~| s| \(..:..\):[^ ]* +.... | \\1 | " \ | sort \ | tac } fixnl() { # # Fix newlines in stdin and pass to stdout # # Note: We need to read whole stdin; this cannot work # for infinite stream. # # Fix annoying cases: # # * If multi-line text is missing newline at the # end---add the missing newline. # # * If -c is passed, and single-line text does have # a newline at the end, remove it. # # This will not touch properly terminated multi-line texts, # or zero-line texts (ie. oly chars with no newline at all). # local arg=$1 # argument passed local cache # cache to keep stream in local nlcount # count of newlines in the stream local lastchr # hex dump (2-digit, lowercase) of last char local single=keep # single-line streams: # keep: do nothing # chop: drop last char if it's a LF case $arg in -c|--chop-single) single=chop ;; esac cache="$(mktemp -t fixnl.XXXXXXXX)" cat >"$cache" nlcount=$(<"$cache" wc -l) lastchr=$(<"$cache" tail -c1 | hexdump -e '"%02x"') case $nlcount:$lastchr:$single in 0:??:*) cat "$cache" ;; # 'abc' => keep as is 1:0a:chop) head -c -1 "$cache" ;; # 'abc\n' => -c passed: chop! 1:0a:keep) cat "$cache" ;; # 'abc\n' => keep as is *:0a:*) cat "$cache" ;; # 'a\nb\nc\n' => keep as is *:??:*) cat "$cache"; echo ;; # 'a\nb\nc' => add the missing NL esac rm "$cache" } nlfor() { # # Replace $1 (or blank space) with newlines and fix final newline # # Shorthand for commonly used tr syntax. Example: # # $ echo "$PATH" | nlat : # /foo # /bar # $ # # is almost like `tr : '\n'` except that it is a bit easier # to type and fixes the annoying problem with missing # newline at the end of the replaced string. # local char=$1 test -n "$char" || char='[:blank:]' tr "$char" '\n' \ | fixnl } nljoin() { # # Join lines with $1 (or space) # # Shorthand for commonly used tr syntax. Example: # # $ { echo foo; echo bar; } | nljoin : # # is almost like `tr '\n' :` except that it is a bit easier # to type and fixes the annoying problem with extraneous # newline/colon at the end of final string. # local char=$1 test -n "$char" || char=' ' tr '\n' "$char" \ | sed "s/$char*$//" \ | fixnl -c } urle() { # # Encode or decode (if $1 is '-d') message on stdin as URL encode # local fn=quote case $1 in -d) fn=unquote ;; -*) echo 'usage: urle [-d] &2; return 2 ;; esac python3 -c "import sys; from urllib.parse import $fn; print($fn(sys.stdin.read()));" } qpr() { # # Encode or decode (if $1 is '-d') message on stdin as Quoted Printable # local fn=encode case $1 in -d) fn=decode ;; -*) echo 'usage: qpr [-d] &2; return 2 ;; esac perl -MMIME::QuotedPrint -pe "\$_=MIME::QuotedPrint::$fn(\$_);" } xop() { # # Common clipboard operations with fixnl() on top # local op=$1 local file=${2:-/dev/stdin} case $op in oo) xclip -selection clipboard -o | fixnl ;; o) xclip -o | fixnl ;; ii) fixnl -c | xclip -selection clipboard -i ;; i) fixnl -c | xclip -i ;; esac <"$file" } xod() { # # Like mktemp but get the content from clipboard # # Dump xo in a file named $1 somewhere in /tmp; echo the path # usage: scp $(xod useful_name.txt) eg:some/shared/place # instead of: # # xo > useful_name.txt # scp useful_name.txt eg:some/shared/place # rm useful_name.txt # local name="${1:-clipboard_dump.txt}" local tmp tmp=$(mktemp -d -t "xod.XXXXXXXX") xclip -o > "$tmp/$name" echo "$tmp/$name" } xood() { # # Just like xod() but using xoo (i.e. 'clipboard' clipboard) # local name="${1:-clipboard_dump.txt}" local tmp tmp=$(mktemp -d -t "xood.XXXXXXXX") xclip -selection clipboard -o > "$tmp/$name" echo "$tmp/$name" } xl() { # # Show primary clipboard in less(1) # xop o | less -S } xxl() { # # Show C-C clipboard in less(1) # xop oo | less -S } xvxx() { # # Edit text in primary clipboard and save it to C-C clipboard # # Ideal for editing snippets in browser-based editors: during editing, # select the text, open terminal, call `xvxx`, edit the text, move # back to the browser and paste it over the old (still selected) text. # That's it, no need to make up and save temporary files. # # If you quickly realize you need to re-edit the text, use xvvx(). # xop o | vipe | xop ii } xcp() { # # Copy paths of $@ to clipboard # local path find "$@" -maxdepth 0 -mindepth 0 \ | while read -r path; do readlink -e "$path" done \ | xop i } xpst() { # # Paste paths from clipboard # { xop o; echo; } \ | while read -r path; do echo "path='$path'" >&2 test -e "$path" || { echo "does not exist: $path" continue } cp -r "$path" . done } xvb() { # # Edit text in primary clipboard and run it using bash # xop o | vipe | bash } xxvb() { # # Edit text in C-C clipboard and run it using bash # xop oo | vipe | bash } vxx() { # # Edit text on stdin and save it to C-C clipboard # # Ideal for editing outut of command before pasting ot to browser # or another GUI application. Run the command with `vxx`, edit # the text, move back to the application and paste it. # # If you quickly realize you need to re-edit the text, use xvvx(). # vipe | xop ii } xcxx() { # # Filter text in primary clipboard using command $@ and save it to C-C clipboard # # Similar to xvvx() but instead of interactive editing, provided filter # command is run. # local cmd=("$@") xop o | "${cmd[@]}" | xop ii return "${PIPESTATUS[1]}" } vx() { # # Edit stdin and save it to primary clipboard # # Ideal for selecting snippets of output of arbitrary commands. # select the text, open terminal, call `xvx`, edit the text, move # back to the browser and paste it over the old (still selected) text. # That's it, no need to make up and save temporary files. # vipe | xop i } xxvxx() { # # Edit text in C-C clipboard and save it back # xop oo | vipe | xop ii } yt2ogg() { # # Download YouTube video as vorbis audio # local url=$1 youtube-dl -x --audio-format vorbis "$url" } yum_hasbin() { # # Ask yum who has bin $1 (and make the output actually readable) # local bname for bname in "$@"; do case $bname in */*) dnf provides "$bname" ;; *) dnf provides "*/bin/$bname" ;; esac \ | grep '^.' \ | grep -E '^[[:alnum:]_:.-]+ :' done } cal() { # # cal with the proper version pick # local cal_v local cal_es cal_v=$(command cal -V 2>/dev/null); cal_es=$? case $cal_es:$cal_v in 0:cal\ from\ util-linux\ 2.*) command cal --color=always --monday --week "$@" ;; 64:*) command cal -M "$@" ;; esac } ### .... ### ### BASH ### ### '''' ### HISTCONTROL=ignoredups:erasedups shopt -s histappend PROMPT_COMMAND="history -n; history -w; history -c; history -r; $PROMPT_COMMAND" HISTIGNORE="$HISTIGNORE:ls:ll:la:cd" HISTIGNORE="$HISTIGNORE:git dc:git st" HISTIGNORE="$HISTIGNORE:reset" HISTIGNORE="$HISTIGNORE:se *:sc *" HISTSIZE=-1 HISTFILESIZE=100000 HISTTIMEFORMAT='%F %T ' GLOBIGNORE=.:.. shopt -s histverify # some more aliases alias cls='clear' alias czkrates='czkrates -v' alias ll='ls -lh' alias lla='ls -lha' alias lr='ll -lhrt' alias open='xdg-open' alias diff='colordiff -u' alias dmesg='dmesg --time-format iso' alias pad4='sed -e "/./s/^/ /"' alias mkittool='mkittool -v' alias grep='grep --color' alias sc='se --direction encz.cz' alias taskm='task modify' alias tasks='task rc.context:none' alias ts='ts "%F %T"' alias lsblk='lsblk -o +UUID,LABEL' alias pstree='pstree -h' alias virsh='virsh --connect qemu:///system' alias wttr='curl -s "wttr.in/?1&n&q"' alias xaa='xclip -o | audit2allow' alias xi='xop i' alias xii='xop ii' alias xo='xop o' alias xoo='xop oo' alias reboot="echo -n . ; sync ; echo -n . ; sync ; echo -n . ; systemctl reboot" alias poweroff="echo -n . ; sync ; echo -n . ; sync ; echo -n . ; systemctl poweroff" x4x() { # # Pad text from primary clipboard with 4 spaces; save to C-C clipboard # # ...that is, for inclusion as Markdown verbatim text. # xo | pad4 | xii } RV_TMP="/tmp/bash-rv" mkdir -p "$RV_TMP" ### ...... ### ### OTHERS ### ### '''''' ### export LC_COLLATE=C # make sort upper first export EDITOR=vim export LESSOPEN="| /usr/bin/src-hilite-lesspipe.sh %s" export LESS=' -R ' export NEATY=color export PRETTY=color export PRETTY_DEBUG_EXCLUDE=inigrep export MDVIMB__CONVERTER=cmark export MDVIMB__STYLE=darkzen # pergamen #shellcheck disable=SC2034 { GIT_PS1_SHOWDIRTYSTATE=true GIT_PS1_SHOWUNTRACKEDFILES=true __SATURNIN_COMPLETE_DEBUG=true GIT_DISABLED_COMMANDS="$HOME/.gittum/disabled-commands" } export GIT_PAGER='less -S' # disable mounting things like SFTP to ~/.gvfs when accessed # via GIO (used by nautilus etc.) export GVFS_DISABLE_FUSE=1 # disable the terrible beep sound (only for X; for tty?, blacklist pcspkr) xhost >& /dev/null && xset b off # get rid of those .pyc files once and for all export PYTHONDONTWRITEBYTECODE=1 ssh-add -l >& /dev/null || ssh-add