From 253fa549f1108bb732674fad5b4bec29c23ffd98 Mon Sep 17 00:00:00 2001 From: Ian Kelling Date: Sat, 9 Aug 2014 06:31:44 -0700 Subject: [PATCH] various updates --- .bashrc | 315 +++++++++++++++++++++++++++++++--------------- path_add-function | 63 ++++++---- 2 files changed, 255 insertions(+), 123 deletions(-) diff --git a/.bashrc b/.bashrc index 712d599..ed0084b 100644 --- a/.bashrc +++ b/.bashrc @@ -5,24 +5,33 @@ #exec 2>/a/tmp/bashlog -# By default this file is sourced for all ssh commands. This is wonky. -# Normally, this file is not sourced when a script is run, and it would be much -# better and more consistent if that also happened when when running a script -# over ssh. so here we test for conditions of a script under ssh and return if -# so. we can override with ssh -t which sets $SSH_TTY, which we can detect -# But inside a script, ssh -t won't work, because we aren't using a tty at all. -# So we need something else. Command lines and env variables sent across ssh are strictly limited. -# We could override an obscure unused LC_var, like telephone, or we could transfer a file. -# But I choose to set SendEnv and AcceptEnv ssh vars for BASH_LOGIN_SHELL. -# In a private file, i have aliases for if $- == *i*, ssh -t, else ssh. - -[[ $- != *i* && ! $SSH_CONNECTION ]] && export BASH_LOGIN_SHELL=true - +# By default this file is sourced for ALL ssh commands. This is wonky. +# Normally, this file is not sourced when a script is run, but we can override +# that by having #!/bin/bash -l. +# I want something similar for ssh commands. when a local script runs an ssh command, +# this file should not be sourced by default, but we should be able to override that. +# +# so here we test for conditions of a script under ssh and return if so. To test +# for an overriding condition, we have a few options. one is to use an +# environment variable. env variables sent across ssh are strictly limited. ssh +# -t which sets $SSH_TTY, but within a script that won't work because tty +# allocation will fail. We could override an obscure unused LC_var, like +# telephone, but I don't want to run into some edge case where that messes +# things up. we could transfer a file which we could test for, but I can't think +# of a way to make that inherently limited to a single ssh command. I choose to +# set SendEnv and AcceptEnv ssh config vars to allow the environment variable +# BASH_LOGIN_SHELL to propagate across ssh. + +# assume we want ssh commands to source this file if we are sourcing it, +# and we haven't specified otherwise already +[[ ! $BASH_LOGIN_SHELL ]] && export BASH_LOGIN_SHELL=true + +# first conditions show that we are an ssh command without an interactive shell if [[ $SSH_CONNECTION ]] \ - && [[ $- == *c* ]] \ - && [[ ! $SSH_TTY ]] \ - && [[ ! $BASH_LOGIN_SHELL == true ]] \ - && [[ $- != *i* ]]; then + && [[ $- == *c* ]] \ + && [[ ! $SSH_TTY ]] \ + && [[ $- != *i* ]] \ + && [[ ! $BASH_LOGIN_SHELL == true ]]; then return fi @@ -30,8 +39,6 @@ fi - - ############ # settings # ############ @@ -44,14 +51,13 @@ unalias -a # remove gnome keyring warning messages # there is probably a more proper way, but I didn't find any easily on google -unset GNOME_KEYRING_CONTROL +# now using xfce+xmonad instead of vanilla xmonad, so disabling this +#unset GNOME_KEYRING_CONTROL -#use extra globing features. See man bash, search extglob. +# use extra globing features. shopt -s extglob -#include .files when globbing. -shopt -s dotglob -#but ignore files name . and .. -# this also sets dotglob, but no harm in setting it explicitly +# include .files when globbing, but ignore files name . and .. +# setting this also sets dotglob export GLOBIGNORE=*/.:*/.. # broken with bash_completion package. Saw a bug for this once. Don't anymore. @@ -85,11 +91,14 @@ shopt -s globstar # inside emacs fixes if [[ $INSIDE_EMACS ]]; then + # EMACS is used by bash on startup, but we don't need it anymore. + # plus I hit a bug in a makefile which inherited it + unset EMACS export INSIDE_EMACS export PAGER=cat export MANPAGER=cat - # for readline-complete.el - stty echo + # scp completion does not work, but this doesn't fix it. todo, figure this out + complete -r scp &> /dev/null # todo, remote file completion fails, figure out how to turn it off fi @@ -97,6 +106,8 @@ fi if [[ $- == *i* ]]; then # for readline-complete.el if [[ $INSIDE_EMACS ]]; then + # all for readline-complete.el + stty echo bind 'set horizontal-scroll-mode on' bind 'set print-completions-horizontally on' bind '"\C-i": self-insert' @@ -155,24 +166,25 @@ C_DEFAULT_DIR=/a ## include files ### ################### -for x in $HOME/bin/bash-programs-by-ian/repos/*/*-function; do - source "$x" +for _x in $HOME/bin/bash-programs-by-ian/repos/*/*-function ~/opt/distro-functions/src/*; do + source "$_x" done -source $HOME/identify-distro-functions +unset _x source $HOME/bin/semi-private # so I can share my bashrc source $HOME/path_add-function path_add --ifexists /a/opt/adt-bundle*/tools /a/opt/adt-bundle*/platform-tools path_add $HOME/bin/bash-programs-by-ian/utils - +source $HOME/mw_vars ############### ### aliases ### ############### -if [[ $- == *i* ]]; then - alias cp='cp -i' - alias mv='mv -i' -fi +# disabled for now, but these are generally good +# if [[ $- == *i* ]]; then +# alias cp='cp -i' +# alias mv='mv -i' +# fi # remove any default aliases for these alias ls > /dev/null 2>&1 && unalias ls @@ -200,8 +212,7 @@ if [[ $- == *i* ]]; then else s() { if [[ $EUID != 0 || $1 == -* ]]; then - local SUDOD="$PWD" - sudo -i "$@" + SUDOD="$PWD" sudo -i "$@" else "$@" fi @@ -253,6 +264,15 @@ _debian_pick_mirror_grep () { echo "${x//\//\\/}" } +# portable daemon, for debian & fedora +pdaemon () { + if isdeb; then + sudo /etc/init.d/$1 $2 + else + sudo systemctl $2 $1.service + fi +} + a() { beet "${@}" } @@ -276,15 +296,19 @@ grr() { grep -ri --binary-files=without-match --color=auto "$@" } +pub() { + rsync -rhc /a/h/_site/ li:/var/www/iankelling.org/public_html +} + bashrcpush () { local startdir="$PWD" cd ~ for x in "$@"; do - ssh $x mkdir -p bin - tar cz bin/bash-programs-by-ian bin/semi-private | ssh $x tar xz + ssh $x mkdir -p bin opt/distro-functions + tar cz bin/bash-programs-by-ian bin/semi-private opt/distro-functions/src | ssh $x tar xz done cd $(mktemp -d) - cp /a/c/repos/bash/!(.git) . + command cp /a/c/repos/bash/!(.git) ~/.gitconfig . for x in "$@"; do tar cz * | ssh $x tar xz done @@ -296,6 +320,47 @@ k() { grep -P "$@" ${HISTFILE:-~/.bash_history} | tail -n 40; } calc() { echo "scale=3; $*" | bc -l; } +# diff config files, +# setup for format of postfix +# option = stuff[,] +# [more stuff] +cdiff() { + + local pastline + local unified="$(mktemp)" + local f1="$(mktemp)" + local f2="$(mktemp)" + + _cdiff-prep "$1" "$f1" + _cdiff-prep "$2" "$f2" + cat "$f1" "$f2" | grep -Po '^[^=]+=' | sort | uniq > "$unified" + while IFS= read -r line; do + # the default bright red / blue doesn't work in emacs shell + dwdiff -cblue,red -A best -d " ," <(grep "^$line" "$f1" || echo ) <(grep "^$line" "$f2" || echo ) | colordiff + done < "$unified" +} + + +# join options which are continued to multiples lines onto one line +_cdiff-prep() { + local first=true + grep -vE '^([ \t]*#|^[ \t]*$)' "$1" | while IFS= read -r line; do + # remove leading spaces/tabs. assumes extglob + if [[ $line == "[ ]*" ]]; then + line="${line##+( )}" + fi + if $first; then + pastline="$line" + first=false + elif [[ $line == *=* ]]; then + echo "$pastline" >> "$2" + pastline="$line" + else + pastline="$pastline $line" + fi + done + echo "$pastline" >> "$2" +} # makes it so chown -R symlink affects the symlink and its target. chown() { @@ -386,6 +451,15 @@ git_empty_branch() { # start an empty git branch. carefull, it deletes untracked git clean -fdx } + +ff() { + if type -P firefox &>/dev/null; then + firefox "$@" + else + iceweasel "$@" + fi +} + fw() { firefox -P default "$@" >/dev/null 2>&1 } @@ -432,6 +506,7 @@ l() { } + lld() { ll -d "$@"; } @@ -478,62 +553,6 @@ despace() { -# package manager -# aliases would be much more compact, but they can't be used as ssh commands -# also, to be used in a script, you need -i which prints annoying -# warnings. instead, use -l in a script to source this file -if type -p yum > /dev/null; then - p() { - if [[ $EUID == 0 ]]; then - yum "$@" - else - sudo yum "$@" - fi - } - pi() { - if [[ $EUID == 0 ]]; then - yum -y install "$@" - else - sudo yum -y install "$@" - fi - } - pf() { - if [[ $EUID == 0 ]]; then - yum search "$@" - else - sudo yum search "$@" - fi - } -else - p() { - if [[ $EUID == 0 ]]; then - aptitude "$@" - else - sudo aptitude "$@" - fi - } - pi() { - if [[ $EUID == 0 ]]; then - aptitude -y install "$@" - else - sudo aptitude -y install "$@" - fi - } - pf() { - # scratch a very annoying itch. - # package description width as wide as the screen, and package name field small - # aptitude manual can't figure out how wide emacs terminal is, - # of course it doesn't consult the $COLUMNS variable... - # and in a normal terminal, it makes the package name field ridiculously big - # also, remove that useless dash before the description - if [[ $EUID == 0 ]]; then - aptitude -F "%c%a%M %p %$((COLUMNS - 30))d" -w $COLUMNS search "$@" - else - sudo aptitude -F "%c%a%M %p %$((COLUMNS - 30))d" -w $COLUMNS search "$@" - fi - } -fi - # test existence / exists te() { @@ -544,6 +563,11 @@ te() { return $ret } +# show make targets, via http://stackoverflow.com/questions/3063507/list-goals-targets-in-gnu-make +make-targets() { + make -qp | awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}' +} + # fix root file ownership for FILE argument. # check if parent or grandparent is not root and if the dir of FILE is also @@ -564,6 +588,94 @@ perm_fix() { fi } +# see notes for usage +fsdiff () { + local missing=false + local dname="${PWD##*/}" + local m="/a/tmp/$dname-missing" + local d="/a/tmp/$dname-diff" + [[ -e $d ]] && rm "$d" + [[ -e $m ]] && rm "$m" + local msize=0 + local fsfile + while read -r line; do + fsfile="$1${line#.}" + if [[ -e "$fsfile" ]]; then + md5diff "$line" "$fsfile" && tee -a "/a/tmp/$dname-diff" <<< "$fsfile $line" + else + missing=true + echo "$line" >> "$m" + msize=$((msize + 1)) + fi + done < <(find -type f ) + if $missing; then + echo "$m" + (( msize <= 100 )) && cat $m + fi +} + +fsdiff-test() { + cd $(mktemp -d) + echo ok > a + echo nok > b + mkdir c + echo ok > c/d + local x=$(mktemp -d) + mkdir $x/c + echo different > $x/c/d + echo ok > $x/a + fsdiff $x +} +# expected output, with different tmp dirs +# /tmp/tmp.HDPbwMqdC9/c/d ./c/d +# /a/tmp/tmp.qLDkYxBYPM-missing +# ./b + + +# test whether missing files were renamed, generally for use with fsdiff +# $1 = fsdiff output file, $2 = directory to compare to. pwd = fsdiff dir +# echos non-renamed files +rename-test() { + local x y found + unset sums + for x in "$2"/*; do + { sums+=( "$(md5sum < "$x")" ) ; } 2>/dev/null + done + while read -r line; do + { missing_sum=$(md5sum < "$line") ; } 2>/dev/null + renamed=false + for x in "${sums[@]}"; do + if [[ $missing_sum == "$x" ]]; then + renamed=true + break + fi + done + $renamed || echo "$line" + done < "$1" + return 0 +} + + +# get a random string +#par2rbase=$(head -c 50 /dev/urandom | tr -cd '[:alpha:]') +par2r() { + [[ $par2rbase ]] || { echo "set \$par2rbase first"; return 1; } + d="$PWD" + for x in **; do + if [[ -d $x ]]; then + cd "$x" + par2 c QDLDeDJ6z4.par2 * + cd "$d" + fi + done + +} + +md5diff() { + [[ $(md5sum < "$1") != $(md5sum < "$2") ]] +} + + pfind() { #find *$1* in $PATH [[ $# != 1 ]] && { echo requires 1 argument; return 1; } local pathArray @@ -571,10 +683,8 @@ pfind() { #find *$1* in $PATH find "${pathArray[@]}" -iname "*$1*" } - -pwd() { # do pwd + some other info. - echo "$(ll -d "$PWD") $USER@$HOSTNAME $(date +%r)" -} +# do pwd + some other info. +#pwd() { echo "$(ll -d "$PWD") $USER@$HOSTNAME $(date +%r)"; } pwgen() { # generate a random password, with digits & punctuation and without @@ -582,6 +692,7 @@ pwgen() { # generate a random password, with digits & punctuation and without head -c 200 /dev/urandom | tr -cd '[:graph:]' | head -c "$arg" echo head -c 200 /dev/urandom | tr -cd '[:alnum:]' | head -c "$arg" + head -c 5 /dev/urandom | tr -cd '[:alpha:]' | head -c "$arg" echo } @@ -604,7 +715,7 @@ pick-trash() { local nth=1 # last condition is to not ask again for ones we skipped while name="$( echo | restore-trash | gr "$PWD/[^/]\+$" | gr "$1" )" \ - && [[ $name ]] && (( $(wc -l <<<"$name") >= nth )); do + && [[ $name ]] && (( $(wc -l <<<"$name") >= nth )); do name="$(echo "$name" | head -n $nth | tail -n 1 )" read -p "$name [Y/n] " ask if [[ ! $ask || $ask == [Yy] ]]; then @@ -794,7 +905,7 @@ hl() { # history limit. Write extra history to archive file. if [[ $- == *i* ]]; then # commands to run when bash exits normally - trap "hl; smh" EXIT + trap "hl; _smh" EXIT fi diff --git a/path_add-function b/path_add-function index 428e2ec..0edf2bb 100644 --- a/path_add-function +++ b/path_add-function @@ -1,20 +1,28 @@ #!/bin/bash -# no bashisms so it can be used in debian profile run by dash -# --start adds to start of path, which will give it highest priority -# --ifexists will add to path only if the directory exists +# avoiding bashisms so it can be used in edge cases where I don't have bash, +# however, I'm not super confident that I've avoided them all +# +# path_add() { - local found x y z ifexists start loop + local help="usage: path_add [options] PATH +--help: print this +--end: adds to end of path, which will give it lowest priority +--ifexists: add to path only if the directory exists" + local found x y z ifexists end loop newpath ifexists=false - start=false + end=false loop=true # portable substring matching is ugly http://mywiki.wooledge.org/BashFAQ/041 while $loop; do case $1 in --*) - if [ "$1" = --start ]; then - start=true + if [ "$1" = --end ]; then + end=true elif [ "$1" = --ifexists ]; then ifexists=true + elif [ "$1" = --help ]; then + echo "$help" + return fi shift ;; @@ -23,22 +31,35 @@ path_add() { ;; esac done - for x in "$@"; do - found=false - IFS=: - for y in $PATH; do - [ "$x" = "$y" ] && found=true + IFS=: + # build up the path without the components we want to add + for y in $PATH; do + for x in "$@"; do + if [ "$x" = "$y" ]; then + found=true + else + found=false + fi done - unset IFS if ! $found; then - if ! $ifexists || [ -d "$x" ]; then - if [ ! "$PATH" ]; then - PATH="$x" - elif $start; then - PATH="$x:$PATH" - else - PATH="$PATH:$x" - fi + if [ ! "$newpath" ]; then + newpath="$y" + else + newpath="$newpath:$y" + fi + fi + done + + unset IFS + PATH="$newpath" + for x in "$@"; do + if ! $ifexists || [ -d "$x" ]; then + if [ ! "$PATH" ]; then + PATH="$x" + elif $end; then + PATH="$PATH:$x" + else + PATH="$x:$PATH" fi fi done -- 2.30.2