mostly fixes
[distro-setup] / brc
diff --git a/brc b/brc
index bd76bb4c8265890c517bdff5f501556ed0d76bcb..02ad1a67b78073f1cb58f6bac878d3e64def4582 100644 (file)
--- a/brc
+++ b/brc
@@ -259,11 +259,6 @@ if [[ $SOE ]]; then
   fi
 fi
 
-# based on readme.debian. dunno if this will break on other distros.
-if [[ -s /usr/share/wcd/wcd-include.sh ]]; then
-  source /usr/share/wcd/wcd-include.sh
-fi
-
 
 mysrc() {
   local path dir file
@@ -391,11 +386,6 @@ for num in {1..9}; do
 done
 
 
-b() {
-  # backwards
-  c -
-}
-
 hexipv4() {
   printf '%d.%d.%d.%d\n' $(echo $1 | sed 's/../0x& /g')
 }
@@ -425,19 +415,226 @@ utcl() { # utc 24 hour time to local hour 24 hour time
   echo "print( ($1  $(date +%z | sed -r 's/..$//;s/^(-?)0*/\1/')) % 24)"|python3
 }
 
-# c. better cd
-if type -p wcd &>/dev/null; then
-  if [[ $LC_INSIDE_EMACS ]]; then
-    c() { wcd -c -z 50 -o "$@"; }
-  else
-    # lets see what the fancy terminal does from time to time
-    c() { wcd -c -z 50 "$@"; }
+declare -a _iankdirf _iankdirb
+
+
+# ## old wcd, to be deleted
+# b() {
+#   # backwards
+#   c -
+# }
+# # shellcheck disable=SC2032
+# f() {
+#   # cd forward
+#   c +
+# }
+# cl() {
+#   # choose recent directory. cl = cd list
+#   c =
+# }
+# # c. better cd
+# if ! type -t c &>/dev/null; then
+#   if type -p wcd &>/dev/null; then
+#     if [[ $LC_INSIDE_EMACS ]]; then
+#       c() { wcd -c -z 50 -o "$@"; }
+#     else
+#       # lets see what the fancy terminal does from time to time
+#       c() { wcd -c -z 50 "$@"; }
+#     fi
+#   else
+#     c() { cd "$@"; }
+#   fi
+# fi
+
+# c. better cd.
+# keep 2 stacks, forward and back. the top of the back is $PWD
+# as long as the last directory change was due to c,b,or cl.
+c() {
+  # normally, the top of dirb is our current dir. if it isn't,
+  # put it on there, except we don't want to do that when we
+  # just launched a shell
+  if [[ $OLDPWD ]]; then
+    if (( ${#_iankdirb[@]} == 0 )) || [[ ${_iankdirb[-1]} != "$PWD" ]]; then
+      _iankdirb+=("$PWD")
+    fi
   fi
-else
-  c() { cd "$@"; }
-fi
+  cd "$@"
+  if (( ${#_iankdirb[@]} == 0 )) || [[ ${_iankdirb[-1]} != "$PWD" ]]; then
+    _iankdirb+=("$PWD")
+  fi
+  echo "$PWD" >> ~/.iankdirs
+}
 ccomp cd c
 
+bwm() {
+  s bwm-ng -T avg -d
+}
+
+b() {
+  local topb
+  if (( ${#_iankdirb[@]} == 0 )); then
+    echo "nothing left to go back to" >&2
+    return 0
+  fi
+  topb="${_iankdirb[-1]}"
+
+  if [[ $topb == "$PWD" ]] && (( ${#_iankdirb[@]} == 1 )); then
+    echo "already on last back entry" >&2
+    return 0
+  fi
+
+
+  if [[ $topb == "$PWD" ]]; then
+    # add to dirf if not already there
+    if (( ${#_iankdirf[@]} == 0 )) || [[ ${_iankdirf[-1]} != "$topb" ]]; then
+      _iankdirf+=("$topb")
+    fi
+    unset "_iankdirb[-1]"
+    cd "${_iankdirb[-1]}"
+  else
+    if (( ${#_iankdirf[@]} == 0 )) || [[ ${_iankdirf[-1]} != "$PWD" ]]; then
+      _iankdirf+=("$PWD")
+    fi
+    cd "$topb"
+  fi
+
+  # give us a peek at what is next in the list
+  # if (( ${#_iankdirb[@]} >= 2 )); then
+  #   printf "%s\n" "${_iankdirb[-2]}"
+  # fi
+}
+
+f() {
+  local topf
+  if (( ${#_iankdirf[@]} == 0 )); then
+    echo "no forward dir left" >&2
+    return 0
+  fi
+  topf="${_iankdirf[-1]}"
+  unset "_iankdirf[-1]"
+  c "$topf"
+
+  # give us a peek at what is next in the list
+  # if (( ${#_iankdirf[@]} )); then
+  #   printf "%s\n" "${_iankdirf[-1]}"
+  # fi
+}
+
+# a b c (d)
+## back
+# a b (c)
+# d
+#back
+#a (b)
+#d c
+#back
+#(a)
+#d c b
+#forward
+#a (b)
+#d c
+#
+# a b c
+## back
+# a b
+# (c)
+## forward
+
+cl() {
+  local i line input start tmpfile
+  local -A buttondirs alines
+  local -a buttons dirs lines
+  buttons=( {a..z} {2..9} )
+  if [[ ! -s ~/.iankdirs ]]; then
+    echo nothing in ~/.iankdirs
+    return 0
+  fi
+
+  i=0
+
+  # note, alternate approach like this, made the following read fail
+  # done < <(tac ~/.iankdirs | awk '!seen[$0]++')
+  # bash: read: read error: 0: Input/output error
+  # which went away by adding a sleep 1 after it.
+
+  mapfile -t lines <~/.iankdirs
+  start=$(( ${#lines[@]} - 1 ))
+
+  # we have ~33 buttons as of this writing, so lets
+  # prune down the history every once in a while.
+  if (( start > 500 )); then
+    tmpfile=$(mktemp)
+    tac ~/.iankdirs | awk '!seen[$0]++' | head -n 200 >$tmpfile
+    cat $tmpfile > ~/.iankdirs
+  fi
+
+  for (( j=$start; j >= 0; j-- )); do
+    line="${lines[$j]}"
+    if [[ ! $line || ${alines[$line]} || ! -d "$line" || $line == "$PWD" || line == "$HOME"  ]]; then
+      continue
+    fi
+    alines[$line]=t
+    buttondirs[${buttons[i]}]="$line"
+    printf "%s %s\n" ${buttons[i]} "$line"
+    if (( i == ${#buttons[@]} - 1 )); then
+      break
+    fi
+    i=$(( i + 1 ))
+  done
+
+  if (( i == 0 )); then
+    echo "no dirs in ~/.iankdirs"
+    return 0
+  fi
+  read -r -N 1 input
+  if [[ $input != $'\n' ]]; then
+    c ${buttondirs[$input]}
+  fi
+}
+bl() {
+  local start i j max
+  max=10
+  start=$(( ${#_iankdirb[@]} - 1 ))
+
+  # cleanup possible repeating of pwd
+  if (( start >= 0 )) && [[ ${_iankdirb[$start]} == "$PWD" ]]; then
+    start=$(( start - 1 ))
+  fi
+  j=1
+  if (( start >= 0 )); then
+    for (( i=$start; i >= 0 ; i-- )); do
+      printf "%s %s\n" $j ${_iankdirb[i]}
+      j=$(( j + 1 ))
+      if (( j >= max )); then
+        break
+      fi
+    done
+  fi
+
+  max=10
+
+  start=$(( ${#_iankdirf[@]} - 1 ))
+
+  # cleanup possible repeating of pwd
+  if (( start >= 0 )) && [[ ${_iankdirf[$start]} == "$PWD" ]]; then
+    start=$(( start - 1 ))
+  fi
+  if (( start < 0 )); then
+    return 0
+  fi
+  echo --
+  j=1
+  for (( i=$start; i >= 0 ; i-- )); do
+    printf "%s %s\n" $j ${_iankdirf[i]}
+    j=$(( j + 1 ))
+    if (( j >= max )); then
+      break
+    fi
+  done
+}
+
+
+
 c4() { c /var/log/exim4; }
 
 caa() { git commit --amend --no-edit -a; }
@@ -490,7 +687,7 @@ chrbind() {
 chumount() {
   local d
   # dev/pts needed for pacman signature check
-  for d in dev proc sys dev/pts; do
+  for d in dev/pts dev proc sys; do
     [[ -d $d ]]
     if mountpoint $d &>/dev/null; then
       m s umount $d
@@ -542,8 +739,8 @@ cdiff() {
 cat-new-files() {
   local start=$SECONDS
   local dir="$1"
-  inotifywait -m "$dir" -e create -e moved_to |
-    # shellcheck disable=SC2030
+  # shellcheck disable=SC2030
+  inotifywait -m "$dir" -e create -e moved_to | \
     while read -r filedir _ file; do
       cat "$filedir$file"
       hr
@@ -569,10 +766,6 @@ cim() {
   git commit -m "$*"
 }
 
-cl() {
-  # choose recent directory. cl = cd list
-  c =
-}
 
 d() { builtin bg "$@"; }
 ccomp bg d
@@ -590,6 +783,19 @@ despace() {
   done
 }
 
+# get ipv4 ip from HOST. or if it is already a number, return that
+hostip() {
+  local host="$1"
+  case $host in
+    [0-9:])
+      echo "$host"
+      ;;
+    *)
+      getent ahostsv4 "$host" | awk '{ print $1 }' | head -n1
+      ;;
+  esac
+}
+
 dig() {
   command dig +nostats +nocmd "$@"
 }
@@ -627,7 +833,10 @@ digdiff() {
 dt() {
   date "+%A, %B %d, %r" "$@"
 }
-ccomp date dt
+dtr() {
+  date -R "$@"
+}
+ccomp date dt dtr
 
 dus() { # du, sorted, default arg of
   du -sh ${@:-*} | sort -h
@@ -635,7 +844,7 @@ dus() { # du, sorted, default arg of
 ccomp du dus
 
 
-e() { echo "$@"; }
+e() { printf "%s\n" "$*"; }
 
 # echo args
 ea() {
@@ -671,7 +880,11 @@ ediff() {
 etail() {
   tail -F /var/log/exim4/mainlog -n 200 "$@"
 }
-ccomp tail etail
+etail2() {
+  tail -F /var/log/exim4/mymain -n 200 "$@"
+}
+
+ccomp tail etail etail2
 
 # print exim old pids
 eoldpids() {
@@ -731,14 +944,18 @@ eless() {
 }
 ccomp less eless
 eqcat() {
-  exiqgrep -i -o 60 | while read -r i; do
+  exiqgrep -ir.\* -o 60 | while read -r i; do
     hlm exim -Mvc $i
     echo
     hlm exigrep $i /var/log/exim4/mainlog | cat ||:
   done
 }
 eqrmf() {
-  exiqgrep -i | xargs exim -Mrm
+  # other ways to get the list of message ids:
+  # exim -bp | awk 'NF == 4 {print $3}'
+  # # this is slower 160ms, vs 60.
+  # exipick -i
+  exiqgrep -ir.\* | xargs exim -Mrm
 }
 
 econfdevnew() {
@@ -755,11 +972,6 @@ econfdev() {
 
 
 
-# shellcheck disable=SC2032
-f() {
-  # cd forward
-  c +
-}
 
 fa() {
   # find array. make an array of file names found by find into $x
@@ -776,19 +988,15 @@ faf() { # find all files. use -L to follow symlinks
        -o -name .undo-tree-history -prune \) -type f 2>/dev/null
 }
 
-# todo: id like to do maybe a daily or hourly cronjob to
-# check that my history file size is increasing. Ive had it
-# inexplicably truncated in the past.
-histrm() {
-  history -n
-  history | awk -v IGNORECASE=1 '{ a=$1; sub(/^( *[^ ]+){4} */, "") }; /'"$*"'/'
-  read -p "press anything but contrl-c to delete"
-  for entry in $(history | awk -v IGNORECASE=1 '{ a=$1; sub(/^( *[^ ]+){4} */, "") }; /'"$*"'/ { print a }' | tac); do
-    history -d $entry
-  done
-  history -w
+# full path without resolving symlinks
+fp() {
+  local dir base
+  base="${1##*/}"
+  dir="${1%$base}"
+  printf "%s/%s\n" $(cd $dir; pwd) "$base"
 }
 
+
 # mail related
 frozen() {
   rm -rf /tmp/frozen
@@ -1118,7 +1326,7 @@ low() {  # make filenames lowercase, remove bad chars
     fi
     f="${arg##*/}"
     new="${f,,}" # downcase
-    new="${new//[^[:alnum:]._-]/_}" # sub bad chars
+    new="${new//[^a-zA-Z0-9._-]/_}" # sub bad chars
     new="${new#"${new%%[[:alnum:]]*}"}" # remove leading/trailing non-alnum
     new="${new%"${new##*[[:alnum:]]}"}"
     # remove bad underscores, like __ and _._
@@ -1142,10 +1350,28 @@ lower() { # make first letter of filenames lowercase.
 k() { # history search
   grep -iP --binary-files=text "$@" ${HISTFILE:-~/.bash_history}  | tail -n 80 || [[ $? == 1 ]];
 }
-ks() { # history search
+ks() { # history search with context
+  # args are an extended regex used by sed
+  history | sed -nr "h;s/^\s*(\S+\s+){4}//;/$*/{g;p}" | tail -n 80 || [[ $? == 1 ]];
+}
+ksu() { # history search unique
   grep -P --binary-files=text "$@" ${HISTFILE:-~/.bash_history}  | uniq || [[ $? == 1 ]];
 }
-ccomp grep k ks
+
+# todo: id like to do maybe a daily or hourly cronjob to
+# check that my history file size is increasing. Ive had it
+# inexplicably truncated in the past.
+histrm() {
+  history -n
+  HISTTIMEFORMAT= history | awk -v IGNORECASE=1 '{ a=$1; sub(/^ *[^ ]+ */, "") }; /'"$*"'/'
+  read -p "press anything but contrl-c to delete"
+  for entry in $(HISTTIMEFORMAT= history | awk -v IGNORECASE=1 '{ a=$1; sub(/^ *[^ ]+ */, "") }; /'"$*"'/ { print a }' | tac); do
+    history -d $entry
+  done
+  history -w
+}
+
+ccomp grep k ks ksu histrm
 
 
 make-targets() {
@@ -1181,7 +1407,15 @@ nags() {
 }
 
 nmt() {
-  s nmtui-connect "$@"
+  # cant use s because sudo -i doesnt work for passwordless sudo command
+  case $EUID in
+    0)
+      sudo nmtui-connect "$@"
+      ;;
+    *)
+      nmtui-connect "$@"
+      ;;
+  esac
 }
 
 nopanic() {
@@ -1349,7 +1583,7 @@ resolvcat() {
   grep '^ *hosts:' /etc/nsswitch.conf
   if systemctl is-enabled systemd-resolved &>/dev/null || [[ $(systemctl is-active systemd-resolved ||:) != inactive ]]; then
     hr; m ser status systemd-resolved | cat || :
-    hr; m systemd-resolve --status | cat
+    hr; m resolvectl status | cat
   fi
 
 }
@@ -1378,6 +1612,10 @@ rmstrips() {
   ssh fencepost head -n 300 /gd/gnuorg/EventAndTravelInfo/rms-current-trips.txt | less
 }
 
+sudo () {
+  command sudo "$@" || return $?
+  DID_SUDO=true
+}
 s() {
   # background
   # I use a function because otherwise we cant use in a script,
@@ -1495,23 +1733,15 @@ sgu() {
 sk() {
 
 
-  # note, if you do something like this
-  # x=( prefix* )
-  # then disable the warning with:
-  # shellcheck disable=SC2206 # globbing is intended
-
-  # 2029: "unescaped, this expands on the client side.": yes, I know how ssh works
-  # 2164: "Use 'cd ... || exit' or 'cd ... || return' in case cd fails.": i have automatic error handling
-  # 2086: unquoted $var: Quoting every var I set is way too much quotes.
-  # 2068: Double quote array expansions to avoid re-splitting elements: same as above.
-  # 2033: command arg is a function name: too many false positives.
+  # disable a warning with:
+  # shellcheck disable=SC2206 # reasoning
 
+  # see bash-template/style-guide.md for justifications
 
-  # these ones I had disabled, but without a good written explanation, so enabling them temporarily
-  # 2046: unquoted $(cmd)
-  # 2119: Functions with optional args get bad warnings when none are passed.
-
-  shellcheck -W 999 -x -e 2029,2164,2086,2068,2033 "$@" || return $?
+  local quotes others
+  quotes=2048,2068,2086,2206
+  others=2029,2033,2054,2164
+  shellcheck -W 999 -x -e $quotes,$others "$@" || return $?
 }
 
 
@@ -1900,6 +2130,12 @@ psnetns() {
       if [[ $x ]]; then echo "$x"; else echo $l; fi;
     done
 }
+nonet() {
+  if ! s ip netns list | grep -Fx nonet &>/dev/null; then
+    s ip netns add nonet
+  fi
+  sudo -E env /sbin/ip netns exec nonet sudo -E -u iank /bin/bash
+}
 
 m() { printf "%s\n" "$*";  "$@"; }
 
@@ -1947,6 +2183,23 @@ s/^\Wcapability: (.*)/\1/;Ta;h;b
 "|sort -r
 }
 
+# Run script by copying it to a temporary location first,
+# and changing directory, so we don't have any open
+# directories or files that could cause problems when
+# remounting.
+z() {
+  local tmp
+  tmp=$(type -p "$1")
+  if [[ $tmp ]]; then
+    cd $(mktemp -d)
+    cp -a "$tmp" .
+    shift
+    ./"${tmp##*/}" "$@"
+  else
+    "$@"
+  fi
+}
+
 # * misc stuff