X-Git-Url: https://iankelling.org/git/?a=blobdiff_plain;f=brc;h=b2df5c28bcd8aa102fc4eef73ca43b69b379610e;hb=768363d8771edb9d9ed82425fa772d77b90139c0;hp=02ad1a67b78073f1cb58f6bac878d3e64def4582;hpb=5abdcfce00c6ff61bf3856f7b5101915dc096107;p=distro-setup diff --git a/brc b/brc index 02ad1a6..b2df5c2 100644 --- a/brc +++ b/brc @@ -5,11 +5,19 @@ # Use source ~/.bashrc instead of doing bash -l when running a script # so this can set extdebug and avoid the bash debugger. + + if [[ -s /a/bin/errhandle/err ]]; then - source /a/bin/errhandle/err -elif [[ -s $bashrc_dir/err ]]; then # shellcheck source=/a/bin/errhandle/err - source $bashrc_dir/err + source /a/bin/errhandle/err + # wtf, shellcheck doesn't allow disabling warnings in elifs +else + # bleh shellcheck can't handle disabling in an elif, so nesting this if. + # shellcheck disable=SC2154 # set in .bashrc + if [[ -s $bashrc_dir/err ]]; then + # shellcheck source=/a/bin/errhandle/err + source $bashrc_dir/err + fi fi # In t8, it runs clear_console for login shells by default. I don't want @@ -224,6 +232,7 @@ export PROFILE_TASKS_TASK_OUTPUT_LIMIT=100 # i for insensitive. the rest from # X means dont remove the current screenworth of output upon exit # R means to show colors n things +# a useful flag is -F aka --quit-if-one-screen export LESS=RXij12 export SYSTEMD_LESS=$LESS @@ -266,8 +275,10 @@ mysrc() { dir=${path%/*} file=${path##*/} if [[ -s $path ]]; then + # shellcheck disable=SC1090 # this is dynamic, shellcheck can't follow it. source $path elif [[ -s $bashrc_dir/$file ]]; then + # shellcheck disable=SC1090 # this is dynamic, shellcheck can't follow it. source $bashrc_dir/$file fi } @@ -276,22 +287,315 @@ mysrc() { mysrc /a/bin/small-misc-bash/ll-function mysrc /a/bin/distro-functions/src/package-manager-abstractions +# things to remember: +# ALT-C - cd into the selected directory +# CTRL-T - Paste the selected file path into the command line +# +# good guide to some of its basic features is the readme file +# https://github.com/junegunn/fzf + +# if [[ -s /usr/share/doc/fzf/examples/key-bindings.bash ]]; then +# source /usr/share/doc/fzf/examples/key-bindings.bash +# fi # * functions -ccomp() { # copy completion - local src=$1 - local c + +### begin FSF section ### + +# Comments before functions are meant to be good useful +# documentation. If they fail at that, please improve them or send Ian a +# note. + +## copy bash completion +# Usage: ORIGINAL_COMMAND TARGET_COMMAND... +# +# It copies how the bash completion works from one command to other +# commands. +ccomp() { + local c src + src=$1 shift if ! c=$(complete -p $src 2>/dev/null); then _completion_loader $src &>/dev/null ||: c=$(complete -p $src 2>/dev/null) || return 0 fi # remove $src( .*|$) - c=${c% $src} - c=${c%% $src *} + c=${c% "$src"} + c=${c%% "$src" *} eval $c $* } +## directory history tracking and navigation. +# +# cd becomes a function, also aliased to c. b to go back, f to go +# forward, cl to list recent directories and choose one. +# +# The finer details you may want to skip: +# +# We also define bl to print the list of back and forward directories. +# +# We keep 2 stacks, forward and back. Unlike with a web browser, the +# forward stack is not erased when going somewhere new. +# +# Recent directories are stored in ~/.cdirs. +# +declare -a _dir_forward _dir_back +c() { + # normally, the top of _dir_back 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 (( ${#_dir_back[@]} == 0 )) || [[ ${_dir_back[-1]} != "$PWD" ]]; then + _dir_back+=("$PWD") + fi + fi + command cd "$@" + if (( ${#_dir_back[@]} == 0 )) || [[ ${_dir_back[-1]} != "$PWD" ]]; then + _dir_back+=("$PWD") + fi + echo "$PWD" >> ~/.cdirs +} +ccomp cd c + +# back +b() { + local top_back + if (( ${#_dir_back[@]} == 0 )); then + echo "nothing left to go back to" >&2 + return 0 + fi + top_back="${_dir_back[-1]}" + + if [[ $top_back == "$PWD" ]] && (( ${#_dir_back[@]} == 1 )); then + echo "already on last back entry" >&2 + return 0 + fi + + + if [[ $top_back == "$PWD" ]]; then + # add to dirf if not already there + if (( ${#_dir_forward[@]} == 0 )) || [[ ${_dir_forward[-1]} != "$top_back" ]]; then + _dir_forward+=("$top_back") + fi + unset "_dir_back[-1]" + command cd "${_dir_back[-1]}" + else + if (( ${#_dir_forward[@]} == 0 )) || [[ ${_dir_forward[-1]} != "$PWD" ]]; then + _dir_forward+=("$PWD") + fi + command cd "$top_back" + fi + + # Interesting feature, not sure I want it. + # give us a peek at what is next in the list + # if (( ${#_dir_back[@]} >= 2 )); then + # printf "%s\n" "${_dir_back[-2]}" + # fi + # + + # c/b/f Implementation notes: + # + # The top of the back is $PWD + # as long as the last directory change was due to c,b,or cl. + # + # Example of stack changes: + # + # 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 + +} +# forward +f() { + local top_forward + if (( ${#_dir_forward[@]} == 0 )); then + echo "no forward dir left" >&2 + return 0 + fi + top_forward="${_dir_forward[-1]}" + unset "_dir_forward[-1]" + c "$top_forward" + + # give us a peek at what is next in the list + # if (( ${#_dir_forward[@]} )); then + # printf "%s\n" "${_dir_forward[-1]}" + # fi +} +# cd list +cl() { + local i line input start + local -A buttondirs alines + local -a buttons dirs lines + buttons=( {a..z} {2..9} ) + if [[ ! -s ~/.cdirs ]]; then + echo nothing in ~/.cdirs + return 0 + fi + + i=0 + + mapfile -t lines <~/.cdirs + 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 + tac ~/.cdirs | awk '!seen[$0]++' | head -n 200 | tac | sponge ~/.cdirs || [[ $? == 141 ]] + 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 ~/.cdirs" + return 0 + fi + read -r -N 1 input + if [[ $input != $'\n' ]]; then + c "${buttondirs[$input]}" + fi +} +# back list +bl() { + local start i j max + max=10 + start=$(( ${#_dir_back[@]} - 1 )) + + # cleanup possible repeating of pwd + if (( start >= 0 )) && [[ ${_dir_back[$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 ${_dir_back[i]} + j=$(( j + 1 )) + if (( j >= max )); then + break + fi + done + fi + + max=10 + start=$(( ${#_dir_forward[@]} - 1 )) + + # cleanup possible repeating of pwd + if (( start >= 0 )) && [[ ${_dir_forward[$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 ${_dir_forward[i]} + j=$(( j + 1 )) + if (( j >= max )); then + break + fi + done +} + +# pee do. run args as a command with output copied to syslog. +# +# Usage: pd [-t TAG] COMMAND... +# +# -t TAG Override the tag in the syslog. The default is COMMAND with +# any path part is removed, eg. for /bin/cat the tag is cat. +# +# You can view the log via "journalctl -t TAG" +pd() { + local tag ret + ret=0 + tag=${1##*/} + case $1 in + -t) tag="$2"; shift 2 ;; + esac + echo "PWD=$PWD command: $*" | logger -t $tag + "$@" |& pee cat "logger -t $tag" || ret=$? + echo "exited with status=$ret" | pee cat "logger -t $tag" + # this avoids any err-catch + (( ret == 0 )) || return $ret +} +ccomp time pd + +# jdo = journal do. Run command as transient systemd service, tailing +# its output in the journal until it completes. +# +# Usage: jdo COMMAND... +# +# Compared to pd: commands recognize this is a non-interactive shell. +# The service is unaffected if our ssh connection dies, no need to run +# in screen or tmux. +# +# Note: The last few lines of any existing entries for a unit by that +# name will be output first, and there will be a few second delay at the +# start of the command, and a second or so at the end. +# +# Note: Functions and aliases obviously won't work, we resolve the +# command to a file. +# +# Note: requires running as root. +jdo() { + local cmd cmd_name jr_pid ret + ret=0 + cmd="$1" + shift + if [[ $EUID != 0 ]]; then + echo "jdo: error: rerun as root" + return 1 + fi + cmd_name=${cmd##*/} + if [[ $cmd != /* ]]; then + cmd=$(type -P "$cmd") + fi + # -q = quiet + journalctl -qn2 -f -u "$cmd_name" & + # Trial and error of time needed to avoid missing initial lines. + # .5 was not reliable. 1 was not reliable. 2 was not reliable + sleep 4 + jr_pid=$! + systemd-run --unit "$cmd_name" --wait --collect "$cmd" "$@" || ret=$? + # The sleep lets the journal output its last line + # before the prompt comes up. + sleep .5 + kill $jr_pid &>/dev/null ||: + unset jr_pid + fg &>/dev/null ||: + # this avoids any err-catch + (( ret == 0 )) || return $ret +} +ccomp time jdo +#### end fsf section + ..() { c ..; } ...() { c ../..; } @@ -313,7 +617,7 @@ chere() { # file cut copy and paste, like the text buffers :) # I havnt tested these. _fbufferinit() { # internal use - ! [[ $my_f_tempdir ]] && my_f_tempdir=$(mktemp -d) + ! [[ $my_f_tempdir ]] && my_f_tempdir="$(mktemp -d)" rm -rf "${my_f_tempdir:?}"/* } fcp() { # file cp @@ -345,8 +649,7 @@ _khfix_common() { ip_entry=$ip host_entry=$host fi - tmpfile=$(mktemp) - if [[ $host != $ip ]]; then + if [[ $host != "$ip" ]]; then key=$(ssh-keygen -F "$host_entry" -f $file | sed -r 's/^.*([^ ]+ +[^ ]+) *$/\1/') if [[ $key ]]; then grep -Fv "$key" "$file" | sponge "$file" @@ -368,6 +671,33 @@ khcopy() { ssh-copy-id $1 } +# ya, hacky hardcoded hostnames in 2023. we could do better +hssh-update() { + local -a failed_hosts hosts + case $HOSTNAME in + sy|kd) + hosts=( + kd x3.office.fsf.org syw + ) + ;; + x3) + hosts=( + b8.nz sywg.b8.nz + ) + ;; + esac + for host in ${hosts[@]}; do + e $host + if ! scp /b/fai/fai/config/files/usr/local/bin/hssh/IANK root@$host:/usr/local/bin/hssh; then + failed_hosts+=($host) + fi + done + if (( ${#failed_hosts[@]} >= 1 )); then + echo failed_hosts=${failed_hosts[*]} + return 1 + fi +} + a() { local x x=$(readlink -nf "${1:-$PWD}") @@ -382,256 +712,82 @@ for field in {1..20}; do done # h1 = head -n1 for num in {1..9}; do - eval h$num"() { head -n$num; }" + eval h$num"() { head -n$num || [[ \$? == 141 ]]; }" done hexipv4() { + # shellcheck disable=SC2046 disable=SC2001 disable=SC2183 # hacks, expected printf '%d.%d.%d.%d\n' $(echo $1 | sed 's/../0x& /g') } vp9() { - local f out outdir in + local f out outdir in fname origdir skip1 + origdir="$PWD" outdir=vp9 - case $1 in - --out) - outdir=$2 - shift 2 - ;; - esac + skip1=false + while [[ $1 == -* ]]; do + case $1 in + # if we got interrupted after 1st phase + -2) + skip1=true + shift + ;; + --out) + outdir=$2 + shift 2 + ;; + esac + done m mkdir -p $outdir + # first pass only uses about 1 cpu, so run in parallel for f; do - out=$PWD/$outdir/$f - in=$PWD/$f - m cd $(mktemp -d) - pwd - m ffmpeg -threads 0 -i $in -g 192 -vcodec libvpx-vp9 -vf scale=-1:720 -max_muxing_queue_size 9999 -b:v 750K -pass 1 -an -f null /dev/null - m ffmpeg -y -threads 0 -i $in -g 192 -vcodec libvpx-vp9 -vf scale=-1:720 -max_muxing_queue_size 9999 -b:v 750K -pass 2 -c:a libvorbis -qscale:a 5 $out - cd - + { + fname="${f##*/f}" + if [[ $f == /* ]]; then + in="$f" + else + in=$origdir/$f + fi + out="$origdir/$outdir/$fname" + mkdir -p /tmp/vp9/$fname + cd /tmp/vp9/$fname + if ! $skip1 && [[ ! -s ffmpeg2pass-0.log ]]; then + # -nostdin or else wait causes ffmpeg to go into stopped state. dunno why, random stackoverflow answer. + m ffmpeg -nostdin -hide_banner -loglevel error -i $in -g 192 -vcodec libvpx-vp9 -vf scale=-1:720 -max_muxing_queue_size 9999 -b:v 750K -pass 1 -an -f null /dev/null + fi + if [[ -e $out ]]; then rm -f $out; fi + m ffmpeg -nostdin -hide_banner -loglevel error -y -i $in -g 192 -vcodec libvpx-vp9 -tile-rows 2 -vf scale=-1:720 -max_muxing_queue_size 9999 -b:v 750K -pass 2 -c:a libvorbis -qscale:a 5 $out + } & done + wait -f + cd "$origdir" } utcl() { # utc 24 hour time to local hour 24 hour time echo "print( ($1 $(date +%z | sed -r 's/..$//;s/^(-?)0*/\1/')) % 24)"|python3 } -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 - 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 )) +# for running in a fai rescue. iank specific. +kdrescue() { + d=vgata-Samsung_SSD_850_EVO_2TB_S2RLNX0J502123D + for f in $d vgata-Samsung_SSD_870_QVO_8TB_S5VUNG0N900656V; do + cryptsetup luksOpen --key-file /p /dev/$f/root crypt-$f-root + cryptsetup luksOpen --key-file /p /dev/$f/o crypt-$f-o 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 + mount -o subvol=root_trisquelaramo /dev/mapper/crypt-$d-root /mnt + mount -o subvol=a /dev/mapper/crypt-$d-root /mnt/a + mount -o subvol=o /dev/mapper/crypt-$d-o /mnt/o + mount -o subvol=boot_trisquelaramo /dev/sda2 /mnt/boot + cd /mnt + chrbind } -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 -} @@ -750,6 +906,10 @@ cat-new-files() { } +chownme() { + s chown -R $USER:$USER "$@" +} + # shellcheck disable=SC2032 chown() { # makes it so chown -R symlink affects the symlink and its target. @@ -770,6 +930,12 @@ cim() { d() { builtin bg "$@"; } ccomp bg d +# f would be more natural, but i already am using it for something +z() { builtin fg "$@"; } +ccomp fg z + +x() { builtin kill %%; } + dc() { diff --strip-trailing-cr -w "$@" # diff content } @@ -783,6 +949,26 @@ despace() { done } +# df progress +# usage: dfp MOUNTPOINT [SECOND_INTERVAL] +# SECOND_INTERVAL defaults to 90 +dfp() { + # mp = mountpoint + local a b mp interval + mp=$1 + interval=${2:-90} + if [[ ! $mp ]]; then + echo "dfp: error, missing 1st arg" >&2 + return 1 + fi + while true; do + a=$(df --output=used $mp | tail -n1) + sleep $interval + b=$(df --output=used $mp | tail -n1) + printf "used mib: %'d mib/min: %s\n" $(( b /1000 )) $(( (b-a) / (interval * 1000 / 60 ) )) + done +} + # get ipv4 ip from HOST. or if it is already a number, return that hostip() { local host="$1" @@ -830,13 +1016,18 @@ digdiff() { diff -u /tmp/digdiff <(digsort $s2 "$@") } +# date in a format i like reading dt() { date "+%A, %B %d, %r" "$@" } dtr() { date -R "$@" } -ccomp date dt dtr +# date with all digits in a format i like +dtd() { + date +%F_%T% "$@" +} +ccomp date dt dtr dtd dus() { # du, sorted, default arg of du -sh ${@:-*} | sort -h @@ -856,7 +1047,8 @@ ea() { printf "%s" "${arg}" |& hexdump -C done } -# echo vars. print var including escapes, etc + +# echo variables. print var including escapes, etc, like xxd for variable ev() { if (( ! $# )); then echo no args @@ -877,15 +1069,30 @@ ediff() { } # mail related +# shellcheck disable=SC2120 # we expect to pass arguments in use outside this file etail() { + ngset + tail -F /var/log/exim4/mainlog /var/log/exim4/*main /var/log/exim4/paniclog /var/log/exim4/*panic -n 200 "$@" + ngreset +} +etailm() { tail -F /var/log/exim4/mainlog -n 200 "$@" } etail2() { tail -F /var/log/exim4/mymain -n 200 "$@" } - ccomp tail etail etail2 +# ran into this online, trying it out +detach() { + ( "$@" &>/dev/null & disown ) +} + +showkeys() { + ssh "$@" cat .ssh/authorized_keys{,2} +} + + # print exim old pids eoldpids() { local configtime pid piduptime now daemonpid @@ -896,7 +1103,7 @@ eoldpids() { fi for pid in $(pgrep -f '^/usr/sbin/exim4( |$)'); do # the daemonpid gets reexeced on HUP (service reloads), keeping its same old timestamp - if [[ $pid == $daemonpid ]]; then + if [[ $pid == "$daemonpid" ]]; then continue fi piduptime=$(awk -v ticks="$(getconf CLK_TCK)" 'NR==1 { now=$1; next } END { printf "%9.0f\n", now - ($20/ticks) }' /proc/uptime RS=')' /proc/$pid/stat) ||: # sometimes pids disappear pretty fast @@ -920,12 +1127,13 @@ etailnew() { } # exim watch as old pids go away ewatchold() { - local configtime pid piduptime now + local configtime pid piduptime now tmpstr local -i count local -a oldpids count=0 while true; do - oldpids=($(eoldpids)) + tmpstr=$(eoldpids) + mapfile -t oldpids <<<"$tmpstr" if (( ! ${#oldpids[@]} )); then return fi @@ -970,6 +1178,20 @@ econfdev() { update-exim4.conf -d /tmp/edev/etc/exim4 -o /tmp/edev/e.conf } +# exim grep in +# show important information about incoming mail in the exim log +egrin() { + sed -rn '/testignore|jtuttle|eximbackup/!s/^[^ ]+ ([^ ]+) [^ ]+ [^ ]+ <= ([^ ]+).*T="(.*)" from (<[^ ]+> .*$)/\1 \4\n \3/p' <${1:-/var/log/exim4/mainlog} +} + +# 2nd line is message-id: +egrinid() { + sed -rn '/testignore|jtuttle|eximbackup/!s/^[^ ]+ ([^ ]+) [^ ]+ [^ ]+ <= ([^ ]+).* id=([^ ]+) T="(.*)" from (<[^ ]+> .*$)/\1 \5\n \3\n \4/p' <${1:-/var/log/exim4/mainlog} +} +etailin() { + tail -F /var/log/exim4/mainlog | sed -rn '/testignore|jtuttle|eximbackup/!s/^[^ ]+ ([^ ]+) [^ ]+ [^ ]+ <= ([^ ]+).*T="(.*)" from (<[^ ]+> .*$)/\1 \4\n \3/p' +} + @@ -988,12 +1210,75 @@ faf() { # find all files. use -L to follow symlinks -o -name .undo-tree-history -prune \) -type f 2>/dev/null } -# full path without resolving symlinks +# usage ffconcat FILES_TO_CONCAT OUTPUT_FILE +ffconcat() { + local tmpf + tmpf=$(mktemp) + printf "file '%s'\n" "$1" >$tmpf + while (( $# > 1 )); do + shift + printf "file '%s'\n" "$1" >>$tmpf + done + # https://trac.ffmpeg.org/wiki/Concatenate + ffmpeg -f concat -safe 0 -i $tmpf -c copy "$1" + rm $tmpf +} +ffremux() { + local tmpf tmpd + if (( $# == 0 )); then + echo ffremux error expected args >&2 + return 1 + fi + tmpd="$(mktemp -d)" + for f; do + tmpf=$tmpd/"${f##*/}" + ffmpeg -i "$f" -c:v copy -c:a copy $tmpf + cat $tmpf >"$f" + done + rm -r $tmpd +} + + + +# absolute path of file/dir without resolving symlinks. +# +# Most of the time, I want this where I would normally use readlink. +# This is what realpath -s does in most cases, but sometimes it +# actually resolves symlinks, at least when they are in /. +# +# Note, if run on a dir, if the final component is relative, it won't +# resolve that. Use the below fpd for that. +# +# note: we could make a variation of this which +# assigns to a variable name using eval, so that we don't have to do +# x=$(fp somepath), which might save subshell overhead and look nice, +# but I'm not going to bother. fp() { - local dir base - base="${1##*/}" - dir="${1%$base}" - printf "%s/%s\n" $(cd $dir; pwd) "$base" + local initial_oldpwd initial_pwd dir base + initial_oldpwd="$OLDPWD" + initial_pwd="$PWD" + if [[ $1 == */* ]]; then + dir="${1%/*}" + base="/${1##*/}" + # CDPATH because having it set will cause cd to possibly print output + CDPATH='' cd "$dir" + printf "%s%s\n" "$PWD" "$base" + CDPATH='' cd "$initial_pwd" + OLDPWD="$initial_oldpwd" + else + printf "%s/%s\n" "$PWD" "$1" + fi +} +# full path of directory without resolving symlinks +fpd() { + local initial_oldpwd initial_pwd dir + initial_oldpwd="$OLDPWD" + initial_pwd="$PWD" + dir="$1" + CDPATH='' cd "$dir" + printf "%s%s\n" "$PWD" "$base" + cd "$initial_pwd" + OLDPWD="$initial_oldpwd" } @@ -1013,7 +1298,7 @@ frozenrm() { local ids=() while read -r line; do printf '%s\n' "$line" - ids+=($(printf '%s\n' "$line" |gr frozen|awk '{print $3}')) + ids+=("$(printf '%s\n' "$line" |gr frozen|awk '{print $3}')") done < <(s mailq) echo "sleeping for 2 in case you change your mind" sleep 2 @@ -1111,6 +1396,7 @@ g() { if [[ $EMACSDIR ]]; then # Alter the path here, otherwise the nfs mount gets triggered on the # first path lookup when emacs is not being used. + # shellcheck disable=SC2098 disable=SC2097 # false positive PATH="$EMACSDIR/lib-src:$EMACSDIR/src:$PATH" EHOME=$HOME HOME=$EMACSDIR m emacsclient -a "" $args "$@" else if $gdb; then @@ -1119,8 +1405,8 @@ g() { # m gdb -ex="set follow-fork-mode child" -ex=r -ex=quit --args emacs --daemon m emacsclient -a "" $args "$@" sleep 1 - cd /a/opt/emacs-$(distro-name)$(distro-num) - s gdb -p $(pgrep -f 'emacs --daemon') -ex c + cd "/a/opt/emacs-$(distro-name)$(distro-num)" + s gdb -p "$(pgrep -f 'emacs --daemon')" -ex c cd - else m emacsclient -a "" $args "$@" @@ -1160,9 +1446,22 @@ ccomp grep gr grr rg() { grr "$@"; } ccomp grep rg -hr() { # horizontal row. used to break up output - printf "$(tput setaf 5 2>/dev/null ||:)█$(tput sgr0 2>/dev/null||:)%.0s" $(eval echo "{1..${COLUMNS:-60}}") - echo +# recursive everything. search for files/dirs and lines. rs = easy chars to press +re() { + local query + query="$1" + find "$@" -not \( -name .svn -prune -o -name .git -prune \ + -o -name .hg -prune -o -name .editor-backups -prune \ + -o -name .undo-tree-history -prune \) 2>/dev/null | grep -iP --color=auto "$query" + grr -m 5 "$@" +} + +# horizontal row. used to break up output +hr() { + local blocks + # 180 is long enough. + blocks=██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████ + printf "%s\n" "$(tput setaf 5 2>/dev/null ||:)${blocks:0:${COLUMNS:-180}}$(tput sgr0 2>/dev/null||:)" } # highlight hl() { @@ -1173,6 +1472,7 @@ hl() { col=$((60 - input_len)) printf "\e[1;97;41m%s" "$*" if (( col > 0 )); then + # shellcheck disable=SC2046 # needed to work as intended. a better way would be like hr above. printf "\e[1;97;41m \e[0m%.0s" $(eval echo "{1..${col}}") fi echo @@ -1193,9 +1493,13 @@ hrcat() { local f; for f; do [[ -f $f ]] || continue; hr; echo "$f"; cat "$f"; d # On first use, you input username/pass and it gets an oath token so you dont have to repeat # it\'s at ~/.config/hub hub() { - local up uptar updir p - p=/github/hub/releases/ - up=https://github.com/$(curl -s https://github.com$p| grep -o $p'download/[^/]*/hub-linux-amd64[^"]*' | head -n1) + local up uptar updir p re + # example https://github.com/github/hub/releases/download/v2.14.2/hub-linux-amd64-2.14.2.tgz + up=$(wget -q -O- https://api.github.com/repos/github/hub/releases/latest | jq -r .assets[].browser_download_url | grep linux-amd64) + re='[[:space:]]' + if [[ ! $up || $up =~ $re ]]; then + echo "failed to get good update url. got: $up" + fi uptar=${up##*/} updir=${uptar%.tgz} if [[ ! -e /a/opt/$updir ]]; then @@ -1223,6 +1527,21 @@ hub() { i() { git "$@"; } ccomp git i +# git status: +# cvs -qn update + +# git checkout FILE +# cvs update -C FILE + +# git pull +# cvs up[date] + +# potentially useful command translation +# https://fling.seas.upenn.edu/~giesen/dynamic/wordpress/equivalent-commands-for-git-svn-and-cvs/ + +# importing cvs repo into git using git-cvs package: +# /f/www $ /usr/lib/git-core/git-cvsimport -C /f/www-git + ic() { # fast commit all git commit -am "$*" @@ -1233,9 +1552,18 @@ ipp() { git push } - ifn() { - # insensitive find + local glob + glob="$1" + shift + find -L "$@" -not \( -name .svn -prune -o -name .git -prune \ + -o -name .hg -prune -o -name .editor-backups -prune \ + -o -name .undo-tree-history -prune \) -iname "*$glob*" 2>/dev/null +} + +ifh() { + # insensitive find here. args are combined into the search string. + # -L = follow symlinks find -L . -not \( -name .svn -prune -o -name .git -prune \ -o -name .hg -prune -o -name .editor-backups -prune \ -o -name .undo-tree-history -prune \) -iname "*$**" 2>/dev/null @@ -1258,14 +1586,22 @@ istext() { grep -Il "" "$@" &>/dev/null } -jtail() { - journalctl -n 10000 -f "$@" +pst() { + pstree -apnA } -jr() { journalctl "$@" ; } -jrf() { journalctl -f "$@" ; } + +# journalctl with times in the format the --since= and --until= options accept +jrt() { journalctl -e -n100000 -o short-full "$@"; } +jr() { journalctl -e -n100000 "$@" ; } +jrf() { journalctl -n1000 -f "$@" ; } jru() { - journalctl -u exim4 _SYSTEMD_INVOCATION_ID=$(systemctl show -p InvocationID --value $1) + # the invocation id is "assigned each time the unit changes from an inactive + # state into an activating or active state" man systemd.exec + journalctl -e --no-tail -u exim4 _SYSTEMD_INVOCATION_ID="$(systemctl show -p InvocationID --value $1)" } +ccomp journalctl jr jrf jru + + l() { if [[ $PWD == /[iap] ]]; then @@ -1326,6 +1662,7 @@ low() { # make filenames lowercase, remove bad chars fi f="${arg##*/}" new="${f,,}" # downcase + # shellcheck disable=SC2031 # seems like a shellcheck bug new="${new//[^a-zA-Z0-9._-]/_}" # sub bad chars new="${new#"${new%%[[:alnum:]]*}"}" # remove leading/trailing non-alnum new="${new%"${new##*[[:alnum:]]}"}" @@ -1363,14 +1700,19 @@ ksu() { # history search unique # 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 + HISTTIMEFORMAT='' history | awk -v IGNORECASE=1 '{ a=$1; sub(/^ *[^ ]+ */, "") }; /'"$*"'/' + read -r -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 } +# history without the date +histplain() { + history "$@" | cut -d' ' -f 7- +} + ccomp grep k ks ksu histrm @@ -1386,7 +1728,16 @@ mkc() { ccomp mkdir mkc mkct() { - mkc $(mktemp -d) + mkc "$(mktemp -d)" +} +# mkdir the last arg, cp the rest into it +mkcp() { + mkdir -p "${@: -1}" + cp "${@:1:$#-1}" "${@: -1}" +} +mkmv() { + mkdir -p "${@: -1}" + mv "${@:1:$#-1}" "${@: -1}" } mkt() { # mkdir and touch file @@ -1400,12 +1751,24 @@ mkdir() { command mkdir -p "$@"; } nags() { # https://github.com/HenriWahl/Nagstamon/issues/357 - if ! pgrep -f /usr/lib/notification-daemon/notification-daemon >/dev/null; then - /usr/lib/notification-daemon/notification-daemon & + if ! pgrep -f /usr/bin/dunst >/dev/null; then + /usr/bin/dunst & fi /usr/bin/nagstamon & } +# profanity screen +profsrc() { + screen -RD -S profanity +} + +# i dont want to wait for konsole to exit... +prof() { + command prof &>/dev/null & +} + + + nmt() { # cant use s because sudo -i doesnt work for passwordless sudo command case $EUID in @@ -1418,17 +1781,43 @@ nmt() { esac } + +ngset() { + if shopt nullglob >/dev/null; then + ngreset=false + else + shopt -s nullglob + ngreset=true + fi +} +ngreset() { + if $ngreset; then + shopt -u nullglob + fi +} + nopanic() { # shellcheck disable=SC2024 - sudo tee -a /var/log/exim4/paniclog-archive /dev/null) ||: @@ -1444,19 +1833,21 @@ pkx() { # package extract # pgrep and kill pk1() { - local pid - pid=($(pgrep -f "$*")) - case ${#pid[@]} in + local tmpf + local -a pids + tmpf=$(pgrep -f "$*") + mapfile -t pids <<<"$tmpf" + case ${#pids[@]} in 1) # shellcheck disable=SC2128 { - ps -F $pid - m kill $pid + ps -F ${pids[0]} + m kill ${pids[0]} } ;; 0) echo "no pid found" ;; *) - ps -F ${pid[@]} + ps -F ${pids[@]} ;; esac } @@ -1500,8 +1891,9 @@ r() { # scp is insecure and deprecated. scp() { - rsync --inplace "$@" + rsync -Pt --inplace "$@" } +ccomp rsync scp randport() { # available high ports are 1024-65535, @@ -1514,6 +1906,7 @@ EOF # reapply bashrc reb() { + # shellcheck disable=SC1090 # expected to not follow source ~/.bashrc } @@ -1538,8 +1931,9 @@ rst() { # rl without preserving modification time. rsync -ahvic --delete --no-t "$@" } -rsu() { # [OPTS] HOST PATH - # eg. rlu -opts frodo /testpath +# [RSYNC_OPTS] HOST PATH +rsu() { + # eg. rsu -opts frodo /testpath # relative paths will expanded with readlink -f. opts=("${@:1:$#-2}") # 1 to last -2 path="${*:$#}" # last @@ -1547,10 +1941,7 @@ rsu() { # [OPTS] HOST PATH if [[ $path == .* ]]; then path=$(readlink -f $path) fi - # rync here uses checksum instead of time so we dont mess with - # unison relying on time as much. g is for group, same reason - # to keep up with unison. - m s rsync -rlpchviog --relative "${opts[@]}" "$path" "root@$host:/"; + m rsync -ahvi --relative --no-implied-dirs "${opts[@]}" "$path" "root@$host:/"; } ccomp rsync rsd rsa rst rsu @@ -1608,10 +1999,20 @@ reresolv() { fi } +# add annoyingly long argument which should be the default +sedi() { + sed -i --follow-symlinks "$@" +} + rmstrips() { ssh fencepost head -n 300 /gd/gnuorg/EventAndTravelInfo/rms-current-trips.txt | less } +urun () { + umask $1 + shift + "$@" +} sudo () { command sudo "$@" || return $? DID_SUDO=true @@ -1640,12 +2041,14 @@ sb() { # sudo bash -c local SUDOD="$PWD" sudo -i bash -c "$@" } -ccomp sudo s sb +# secret sudo +se() { s urun 0077 "$@"; } +ccomp sudo s sb se safe_rename() { # warn and dont rename if file exists. # mv -n exists, but it\'s silent if [[ $# != 2 ]]; then - echo safe_rename error: $# args, need 2 >2 + echo safe_rename error: $# args, need 2 >&2 return 1 fi if [[ $1 != "$2" ]]; then # yes, we want to silently ignore this @@ -1691,7 +2094,7 @@ setini() { # set a value in a .ini style file if [[ -s $file ]]; then sed -ri -f - "$file" <&2 + echo 'error: missing SL_INFO_DIR env var' >&2 return 1 fi @@ -1925,7 +2343,7 @@ sl() { if $haveinfo && [[ $type == b ]]; then info_sec=${tmp::10} - read files_sec _ < <(find -L $SL_FILES_DIR -printf "%T@ %p\n" | sort -nr || [[ $? == 141 || ${PIPESTATUS[0]} == 32 ]] ) + read -r files_sec _ < <(find -L $SL_FILES_DIR -printf "%T@ %p\n" | sort -nr || [[ $? == 141 || ${PIPESTATUS[0]} == 32 ]] ) files_sec=${files_sec%%.*} if (( files_sec > info_sec )); then dorsync=true @@ -1936,7 +2354,7 @@ sl() { sync_dirname=${SL_FILES_DIR##*/} if [[ ! $SL_FILES_DIR ]]; then - echo error: missing '$SL_FILES_DIR' env var >&2 + echo 'error: missing SL_FILES_DIR env var' >&2 return 1 fi @@ -2006,8 +2424,12 @@ slog() { while getopts "lt" option do case $option in - l ) arg_base=$logdir ;; - t ) do_stamp=true ;; + l) arg_base=$logdir ;; + t) do_stamp=true ;; + *) + echo error: bad option + return 1 + ;; esac done shift $((OPTIND - 1)) @@ -2038,7 +2460,7 @@ srm () { srun() { scp $2 $1:/tmp - ssh $1 /tmp/${2##*/} $(printf "%q\n" "${@:2}") + ssh $1 "/tmp/${2##*/}" "$(printf "%q\n" "${@:2}")" } @@ -2100,15 +2522,23 @@ psoff() { # however, DEBUG is not inherited, so we need to run it outside a function. # And we want to run set -x afterwards to avoid spam, so we cram everything # in here, and then it will run after this function is done. - PROMPT_COMMAND='trap DEBUG; unset PROMPT_COMMAND; PS1="\w \$ "' + # # set as array to satisfy shellcheck, but it is equivalent to setting it as non-array + PROMPT_COMMAND=('trap DEBUG; unset PROMPT_COMMAND; PS1="\w \$ "') } pson() { - PROMPT_COMMAND=prompt-command + PROMPT_COMMAND=(prompt-command) if [[ $TERM == *(screen*|xterm*|rxvt*) ]]; then trap 'settitle "$BASH_COMMAND"' DEBUG fi } +# prometheus node curl +pnodecurl() { + local host + host=${1:-127.0.0.1} + s curl --cert-type PEM --cert /etc/prometheus/ssl/prometheus_cert.pem --key /etc/prometheus/ssl/prometheus_key.pem --cacert /etc/prometheus/ssl/prom_node_cert.pem --resolve prom_node:9100:$host -v https://prom_node:9100/metrics +} + tx() { # toggle set -x, and the prompt so it doesnt spam if [[ $- == *x* ]]; then set +x @@ -2139,6 +2569,35 @@ nonet() { m() { printf "%s\n" "$*"; "$@"; } +# update file. note: duplicated in mail-setup. +# updates $ur u result to true or false +# updates $reload to true if file updated is in /etc/systemd/system +u() { + local tmp tmpdir dest="$1" + local base="${dest##*/}" + local dir="${dest%/*}" + if [[ $dir != "$base" ]]; then + # dest has a directory component + mkdir -p "$dir" + fi + # shellcheck disable=SC2034 # see comment at top of function + ur=false # u result + tmpdir="$(mktemp -d)" + cat >$tmpdir/"$base" + tmp=$(rsync -ic $tmpdir/"$base" "$dest") + if [[ $tmp ]]; then + printf "%s\n" "$tmp" + # shellcheck disable=SC2034 # see comment at top of function + ur=true + if [[ $dest == /etc/systemd/system/* ]]; then + # shellcheck disable=SC2034 # see comment at top of function + reload=true + fi + fi + rm -rf $tmpdir +} + + uptime() { if type -p uprecords &>/dev/null; then uprecords -B @@ -2187,11 +2646,11 @@ s/^\Wcapability: (.*)/\1/;Ta;h;b # and changing directory, so we don't have any open # directories or files that could cause problems when # remounting. -z() { +zr() { local tmp tmp=$(type -p "$1") if [[ $tmp ]]; then - cd $(mktemp -d) + cd "$(mktemp -d)" cp -a "$tmp" . shift ./"${tmp##*/}" "$@" @@ -2200,6 +2659,97 @@ z() { fi } + +# * spark +# spark 1 5 22 13 53 +# # => ▁▁▃▂▇ + +# The MIT License +# Copyright (c) Zach Holman, https://zachholman.com +# https://github.com/holman/spark + +# As of 2022-10-28, I reviewed github forks that had several newer +# commits, none had anything interesting. I did a little refactoring +# mostly to fix emacs indent bug. + +# Generates sparklines. +_spark_echo() +{ + if [ "X$1" = "X-n" ]; then + shift + printf "%s" "$*" + else + printf "%s\n" "$*" + fi +} + + +spark() +{ + local f tc + local n numbers= + + # find min/max values + local min=0xffffffff max=0 + + for n in ${@//,/ } + do + # on Linux (or with bash4) we could use `printf %.0f $n` here to + # round the number but that doesn't work on OS X (bash3) nor does + # `awk '{printf "%.0f",$1}' <<< $n` work, so just cut it off + n=${n%.*} + (( n < min )) && min=$n + (( n > max )) && max=$n + numbers=$numbers${numbers:+ }$n + done + + # print ticks + local ticks=(▁ ▂ ▃ ▄ ▅ ▆ ▇ █) + + # use a high tick if data is constant + (( min == max )) && ticks=(▅ ▆) + + tc=${#ticks[@]} + f=$(( ( (max-min) <<8)/( tc - 1) )) + (( f < 1 )) && f=1 + + for n in $numbers + do + _spark_echo -n ${ticks[$(( (((n-min)<<8)/f) ))]} + done + _spark_echo +} + +pdfwc() { local f; for f; do echo "$f" "$(pdfinfo "$f" | awk '/^Pages:/ {print $2}')"; done } + + +# nvm install script appended this to my .bashrc. I dont want to run it all the time, +# so put it in a function. +nvm-init() { + export NVM_DIR="$HOME/.nvm" + # shellcheck disable=SC1091 # may not exist, & third party + [ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh" # This loads nvm + # shellcheck disable=SC1091 # may not exist, & third party + [ -s "$NVM_DIR/bash_completion" ] && source "$NVM_DIR/bash_completion" # This loads nvm bash_completion +} + + +leap-year() { + if date -d 'february 29' &>/dev/null; then + year_days=366 + else + year_days=365 + fi + echo $year_days +} + +# on-battery +on-bat() { + if [[ -e /sys/class/power_supply/AC/online && $(/dev/null; then term_bold="$(tput bold)" term_red="$(tput setaf 1)" term_green="$(tput setaf 2)" + # shellcheck disable=SC2034 # expected term_yellow="$(tput setaf 3)" term_purple="$(tput setaf 5)" term_nocolor="$(tput sgr0)" # no font attributes @@ -2262,15 +2813,6 @@ if [[ $- == *i* ]]; then history -a # save history fi - # assigned in brc2 - # shellcheck disable=SC1303 - if [[ $jr_pid ]]; then - if [[ -e /proc/$jr_pid ]]; then - kill $jr_pid - fi - unset jr_pid - fi - case $return in 0) ps_color="$term_purple" ps_char='\$' @@ -2289,11 +2831,15 @@ if [[ $- == *i* ]]; then # faster than sourceing the file im guessing if [[ -e /dev/shm/iank-status && ! -e /tmp/quiet-status ]]; then - eval $(< /dev/shm/iank-status) + eval "$(< /dev/shm/iank-status)" fi if [[ $MAIL_HOST && $MAIL_HOST != "$HOSTNAME" ]]; then ps_char="@ $ps_char" fi + jobs_char= + if [[ $(jobs -p) ]]; then + jobs_char='j\j ' + fi # We could test if sudo is active with sudo -nv # but then we get an email and log of lots of failed sudo commands. # We could turn those off, but seems better not to. @@ -2303,13 +2849,13 @@ if [[ $- == *i* ]]; then if [[ ! $HISTFILE ]]; then ps_char="NOHIST $ps_char" fi - PS1="${PS1%"${PS1#*[wW]}"} $psudo\[$ps_color\]$ps_char\[$term_nocolor\] " + PS1="${PS1%"${PS1#*[wW]}"} $jobs_char$psudo\[$ps_color\]$ps_char\[$term_nocolor\] " # set titlebar. instead, using more advanced # titelbar below #echo -ne "$_title_escape $HOSTNAME ${PWD/#$HOME/~} \007" } - PROMPT_COMMAND=prompt-command + PROMPT_COMMAND=(prompt-command) if [[ $TERM == screen* ]]; then _title_escape="\033]..2;" @@ -2319,18 +2865,22 @@ if [[ $- == *i* ]]; then _title_escape="\033]0;" fi + # make the titlebar be the last command and the current directory. settitle () { - # this makes it so we show the current command if - # one is running, otherwise, show nothing - if [[ $1 == prompt-command ]]; then + + # These are some checks to help ensure we dont set the title at + # times that the debug trap is running other than the case we + # want. Some of them might not be needed. + if (( ${#FUNCNAME[@]} != 1 || ${#BASH_ARGC[@]} != 2 || BASH_SUBSHELL != 0 )); then return 0 fi - if (( ${#BASH_ARGC[@]} == 1 && BASH_SUBSHELL == 0 )); then - echo -ne "$_title_escape ${PWD/#$HOME/~} " - printf "%s" "$*" - echo -ne "\007" + if [[ $1 == prompt-command ]]; then + return 0 fi + echo -ne "$_title_escape ${PWD/#$HOME/~} " + printf "%s" "$*" + echo -ne "\007" } # note, this wont work: @@ -2354,8 +2904,10 @@ fi # best practice unset IFS -# shellcheck disable=SC1090 -[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm" # Load RVM into a shell session *as a function* +if [[ -s "$HOME/.rvm/scripts/rvm" ]]; then + # shellcheck disable=SC1091 + source "$HOME/.rvm/scripts/rvm" +fi # I had this idea to start a bash shell which would run an initial # command passed through this env variable, then continue on