use_color=true
fi
- if [[ $KONSOLE_PROFILE_NAME ]]; then
- TERM=xterm-256color
- fi
-
- if [[ $TERM == alacritty && ! -e /usr/share/terminfo/a/alacritty ]]; then
- # todo: we should try installing the alacritty terminfo if it is not found
- # https://github.com/alacritty/alacritty/issues/2838
- TERM=xterm-256color
- fi
-
- # copying from the alacritty example above,
- if [[ $TERM == xterm-kitty ]]; then
- if [[ ! -e /usr/share/terminfo/x/xterm-kitty ]]; then
- TERM=xterm-256color
- else
- if [[ -e /a/opt/kitty/shell-integration/bash/kitty.bash ]]; then
- KITTY_SHELL_INTEGRATION=t
- source /a/opt/kitty/shell-integration/bash/kitty.bash
- fi
- fi
- fi
-
# todo: not sure this works in sakura
#stty werase undef
#bind "\C-w": kill-region
# sakura == xterm-256color
# konsole == xterm
- if [[ $TERM != xterm-kitty && $TERM == xterm* ]]; then
+ if [[ $TERM == xterm* ]]; then
# control + arrow keys. for other terminals, see http://unix.stackexchange.com/questions/10806/how-to-change-previous-next-word-shortcut-in-bash
bind '"\e[1;5C": shell-forward-word' 2>/dev/null
bind '"\e[1;5D": shell-backward-word' 2>/dev/null
fi
-case $TERM in
- # fixup broken backspace in chroots
- xterm-kitty|alacritty)
- chroot() {
- TERM=xterm-256color command chroot "$@"
- }
- ;;
-esac
-
export BC_LINE_LENGTH=0
# ansible option
if [[ -s $bashrc_dir/path-add-function ]]; then
source $bashrc_dir/path-add-function
if [[ $SSH_CLIENT ]]; then
- if grep -qF /home/iank/.iank/e/e /etc/exports &>/dev/null; then
- export EMACSDIR=/home/iank/.iank/e/e
- fi
path-add $bashrc_dir
fi
fi
fi
# -q = quiet
journalctl -qn2 -f -u "$cmd_name" &
+ jr_pid=$!
# 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.
done
}
+screenrtp() {
+
+ local ip port xoffset
+ read -r ip port xoffset <<<"$@"
+
+ setxenv
+
+ if [[ ! $port ]]; then
+ port=9999
+ fi
+
+ while true; do
+ # By default, plugged in screen goes to the right side, so we need an
+ # offset that is the same as the laptop's x resolution. If we are in
+ # mirror mode, then we don't need an offset.
+ if [[ ! $xoffset ]]; then
+ xoffset=0
+ laptop_x=$(xrandr | awk '$1 == "LVDS-1" {print $4}' | sed 's/x.*//') || { sleep 1; continue; }
+ total_x=$(xdpyinfo| awk '$1 == "dimensions:" {print $2}' | sed 's/x.*//') || { sleep 1; continue; }
+ screen2_res=$(xrandr | awk '$2 == "connected" && $1 != "LVDS-1" { print $3 }' | sed 's/+.*//')
+ if (( laptop_x < total_x )); then
+ xoffset=$laptop_x
+ fi
+ fi
+
+ m ffmpeg -probesize 50M -thread_queue_size 50 \
+ -video_size $screen2_res -f x11grab -framerate 30 -i :0.0+$xoffset.0 \
+ -vcodec libx264 -g 1 -tune zerolatency -preset ultrafast -pix_fmt yuv420p -x264-params repeat-headers=1 \
+ -f rtp_mpegts rtp://$ip:$port ||:
+
+
+ sleep 1
+ done
+}
+
+setxenv() {
+ if [[ ! $DISPLAY ]]; then
+ export DISPLAY=:0.0
+ fi
+ if [[ ! $XAUTHORITY ]]; then
+ export XAUTHORITY=$HOME/.Xauthority
+ fi
+}
+
#### end fsf section
}
_khfix-common() {
- local host ip port file key tmp
- read -r host ip port < <(timeout -s 9 2 ssh -oBatchMode=yes -oControlMaster=no -oControlPath=/ -v $1 |& sed -rn "s/debug1: Connecting to ([^ ]+) \[([^\]*)] port ([0-9]+).*/\1 \2 \3/p" ||: )
+ local host ip port file key tmp ssh_host alias
+ ssh_host=$1
+ {
+ read -r host ip port
+ read -r alias;
+ # note ":graph:" is needed or else we get a trailing \r out of ssh,
+ # dunno why. web search says terminals add \r, so I tried adding -T
+ # to turn off psuedo terminal, but it didnt help.
+ } < <(timeout -s 9 2 ssh -TN -oBatchMode=yes -oControlMaster=no -oControlPath=/ -v $ssh_host |&
+ sed -rn "s/debug1: Connecting to ([^ ]+) \[([^\]*)] port ([0-9]+).*/\1 \2 \3/p;
+s/^debug1: using hostkeyalias: ([[:graph:]]*).*/\1/p" ||: )
file=$(readlink -f ~/.ssh/known_hosts)
if [[ ! $ip ]]; then
echo "khfix: ssh failed"
return 1
fi
+ ip_entry=$ip
+ host_entry=$host
+ if [[ $alias ]]; then
+ host_entry="$alias"
+ fi
if [[ $port != 22 ]]; then
ip_entry="[$ip]:$port"
- host_entry="[$host]:$port"
- else
- ip_entry=$ip
- host_entry=$host
+ if [[ ! $alias ]]; then
+ host_entry="[$host]:$port"
+ fi
fi
- if [[ $host != "$ip" ]]; then
+ if [[ $host_entry != "$ip_entry" ]]; then
tmp=$(mktemp)
ssh-keygen -F "$host_entry" -f $file >$tmp || [[ $? == 1 ]] # 1 when it doesnt exist in the file
if [[ -s $tmp ]]; then
key=$(sed -r 's/^.*([^ ]+ +[^ ]+) *$/\1/' $tmp)
+ else
+ echo "khfix WARNING: did not find host entry:$host_entry in known_hosts"
fi
rm $tmp
if [[ $key ]]; then
ssh-keygen -F "$ip_entry" -f $file >$tmp || [[ $? == 1 ]]
if [[ -s $tmp ]]; then
key=$(sed -r 's/^.*([^ ]+ +[^ ]+) *$/\1/' $tmp)
+ else
+ echo "khfix WARNING: did not find ip entry:$ip_entry in known_hosts"
fi
rm $tmp
if [[ $key ]]; then
grep -Fv "$key" "$file" | sponge "$file"
fi
- ll ~/.ssh/known_hosts
}
khfix-r() { # known hosts fix without syncing to root user
_khfix-common "$@" || return 1
-o -name .hg -prune -o -name .editor-backups -prune \
-o -name .undo-tree-history -prune \) -printf '%h\0%d\0%p\n' | sort -t '\0' -n \
| awk -F '\0' '{print $3}' 2>/dev/null | while read -r file; do
- hr
- printf "%s\n" "$file"
- hr
- cat "$file"
+ hr "$file"
+ v "$file"
+ # if the file is nonempty and the last char is nonempty, it is not
+ # newline terminated.
+ if [[ -s "$file" && "$(tail -c 1 "$file")" ]]; then
+ echo
+ fi
done
}
ccomp cat cf caf
tail -F /var/log/exim4/mainlog -n 200 "$@"
}
etail2() {
- tail -F /var/log/exim4/mymain -n 200 "$@"
+ tail -F /var/log/exim4/nondmain -n 200 "$@"
}
-ccomp tail etail etail2
+# shortcut for tail -F
+ta() {
+ tail -F "$@"
+}
+ccomp tail etail etail2 ta
# ran into this online, trying it out
detach() {
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'
+ local -a tail_arg
+ tail_arg=(-n500)
+ if [[ $1 ]]; then
+ tail_arg=($@)
+ fi
+ tail "${tail_arg[@]}" -F /var/log/exim4/mainlog | sed -rn '/testignore|jtuttle|eximbackup/!s/^[^ ]+ ([^ ]+) [^ ]+ [^ ]+ <= ([^ ]+).*T="(.*)" from (<[^ ]+> .*$)/\1 \4\n \3/p'
}
done < <(find "$@" -print0);
}
+# shellcheck disable=SC2120
faf() { # find all files. use -L to follow symlinks
find "$@" -not \( -name .svn -prune -o -name .git -prune \
-o -name .hg -prune -o -name .editor-backups -prune \
echo "${p%%/.git}"
}
-g() {
-
- local args gdb=false
-
- if [[ $EMACSDIR ]]; then
- path-add "$EMACSDIR/lib-src" "$EMACSDIR/src"
- fi
-
- if [[ $DISPLAY ]]; then
- args=-n
- fi
-
- if (( $# == 0 )); then
- args+=" -c"
- fi
- # duplicate -c, but oh well
- if ! pgrep -u $EUID emacsclient; then
- if (( $# == 0 )) && type -p gdb &>/dev/null; then
- gdb=true
- else
- args+=" -c"
- fi
- fi
- if [[ $EMACSDIR ]]; then
-
- # todo: we don't have to alter HOME since emacs 29+, we can set
- # user-emacs-directory with the flag --init-directory
-
- # 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
- # due to a bug, we cant debug from the start unless we get a new gdb
- # https://sourceware.org/bugzilla/show_bug.cgi?id=24454
- # 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 -
- else
- m emacsclient -a "" $args "$@"
- fi
- fi
-}
# g pipe. like: cmd | emacs. save cmd output to tmp file, then edit.
gp() {
# Don't return 1 on nonmatch because this is meant to be
# interactive, not in a conditional.
if [[ ${#@} == 1 ]]; then
- grep -E --exclude-dir='*.emacs.d' --exclude-dir='*.git' -riIP --color=auto "$@" . || [[ $? == 1 ]]
+ grep --exclude-dir='*.emacs.d' --exclude-dir='*.git' -rniIP --color=auto "$@" . || [[ $? == 1 ]]
else
- grep -E --exclude-dir='*.emacs.d' --exclude-dir='*.git' -riIP --color=auto "$@" || [[ $? == 1 ]]
+ grep --exclude-dir='*.emacs.d' --exclude-dir='*.git' -rniIP --color=auto "$@" || [[ $? == 1 ]]
fi
}
ccomp grep gr grr
# 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||:)"
+ local start end end_count arg
+ # 180 is long enough. 5 for start.
+ start=█████ end=█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
+ end_count=$(( ${COLUMNS:-180} - 5 ))
+ arg="$*"
+ if [[ $arg ]]; then
+ end_count=$(( end_count - 2 - ${#arg} ))
+ start="$start $arg "
+ fi
+ if (( end_count >= 1 )); then
+ end=${end:0:$end_count}
+ else
+ end=
+ fi
+ printf "%s\n" "$(tput setaf 5 2>/dev/null ||:)$start$end$(tput sgr0 2>/dev/null||:)"
}
# highlight
hl() {
grep -P --binary-files=text "$@" ${HISTFILE:-~/.bash_history} | uniq || [[ $? == 1 ]];
}
+# remove lines from history matching $1
+#
# 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.
/usr/bin/nagstamon &
}
-# profanity screen
+# profanity tmux
profsrc() {
- screen -RD -S profanity
+ screen -L profanity a
}
# i dont want to wait for konsole to exit...
fi
x=$(ps -eF)
# final grep is because some commands tend to have a lot of trailing spaces
- y=$(echo "$x" | grep -iP "$@" | grep -o '.*[^ ]') ||:
+ y=$(echo "$x" | sed -r 's,//[^[:space:]:@/]+:[^[:space:]:@/]+@,//REDACTED_URL_USER@PASS/,g' | grep -iP "$@" | grep -o '.*[^ ]') ||:
if [[ $y ]]; then
echo "$x" | head -n 1 || [[ $? == 141 ]]
echo "$y"
systemctl -n 40 status "$@"
}
+# assume last arg is a service and we want to tail its log.
+serj() {
+ local service jr_pid ret
+ ret=0
+ service="${*: -1}"
+ journalctl -qn2 -f -u "$service" &
+ sleep 3
+ s systemctl "$@" || ret=$?
+ sleep .5
+ kill %%
+ (( ret == 0 )) || return $ret
+}
+
seru() { systemctl --user "$@"; }
# like restart, but do nothing if its not already started
srestart() {
systemctl list-unit-files | rg "$@"
}
+# check whether we generally want to do sk on the file
+sk-p() {
+ [[ ! -L $f ]] && istext "$1" && [[ $(head -n1 "$1" 2>/dev/null) == '#!/bin/bash'* ]]
+}
sk() {
# see https://savannah.gnu.org/maintenance/fsf/bash-style-guide/ for justifications
local quotes others ret
quotes=2048,2068,2086,2206,2254
- others=2029,2032,2033,2054,2164,
- shellcheck -W 999 -x -e $quotes,$others "$@" || ret=$?
+ others=2029,2032,2033,2054,2164
+ shellcheck -x -W 999 -e $quotes,$others "$@" || ret=$?
if (( ret >= 1 )); then
echo "A template comment to disable is now in clipboard. eg: # shellcheck disable=SC2206 # reason"
cbs "# shellcheck disable=SC"
return $ret
fi
}
+
# sk with quotes. For checking scripts that we expect to take untrusted
# input in order to verify we quoted vars.
skq() {
shellcheck -W 999 -x -e $others "$@" || return $?
}
-skgit() {
+# sk on all modified & new files in current git repo. must git add for new files.
+skmodified() {
local f
- for f in $(i s | awk '$1 == "modified:" {print $2}'); do
- if istext "$f" && [[ $(head -n1 "$f" 2>/dev/null) == '#!/bin/bash'* ]]; then
+ for f in $(i s | awk '$1 == "modified:" {print $2}; $1 == "new" {print $3}'); do
+ if sk-p "$f"; then
sk $f ||:
fi
done
}
+
+# sk on all the files in current git repo
+skgit() {
+ local f toplevel orig_dir tmp
+ local -a ls_files sk_files
+ toplevel=$(git rev-parse --show-toplevel)
+ if [[ $PWD != "$toplevel" ]]; then
+ orig_dir=$PWD
+ cd $toplevel
+ fi
+ # tracked & untracked files
+ tmp=$(git ls-files && git ls-files --others --exclude-standard)
+ mapfile -t ls_files <<<"$tmp"
+ for f in "${ls_files[@]}"; do
+ if sk-p "$f"; then
+ sk_files+=("$f")
+ fi
+ done
+ sk "${sk_files[@]}"
+ if [[ $orig_dir ]]; then
+ cd $orig_dir
+ fi
+}
+
+
# sl: ssh, but firsh rsync our bashrc and related files to a special
# directory on the remote host if needed.
slr() {
sl --rsync "$@"
}
-sss() { # ssh solo
- sl -oControlMaster=no -oControlPath=/ "$@"
+
+
+# ssh solo
+#
+# WARNING: If you are trying to use -i, remember that keys added to
+# agent previously will still be tried. Use ssh-add -D to remove all
+# keys from the agent.
+sss() {
+ ssh -oControlMaster=no -oControlPath=/ "$@"
}
# kill off old shared socket then ssh
ssk() {
ccomp ssh sl slr sss ssk
# plain ssh
ssh() {
- if [[ $TERM == alacritty || $TERM == xterm-kitty ]]; then
- TERM=xterm-256color LC_USEBASHRC=t command ssh "$@"
- else
- LC_USEBASHRC=t command ssh "$@"
- fi
+ LC_USEBASHRC=t command ssh "$@"
}
# 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.
- # # 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 \$ "')
+ # shellcheck disable=SC2178 # intentional
+ PROMPT_COMMAND='trap DEBUG; unset PROMPT_COMMAND; PS1=" \w \$ "'
}
+
+pskde() {
+ # shellcheck disable=SC2178 # intentional
+ PROMPT_COMMAND='trap DEBUG; unset PROMPT_COMMAND'
+ PS1='\[\e]133;L\a\]\[\e]133;D;$?\]\[\e]133;A\a\]\w \$ \[\e]133;B\a\]' ;
+ PS2='\[\e]133;A\a\]'$PS2'\[\e]133;B\a\]' ;
+ PS0='\[\e]133;C\a\]'
+
+}
+
pson() {
PROMPT_COMMAND=(prompt-command)
if [[ $TERM == *(screen*|xterm*|rxvt*) ]]; then
for n in $numbers
do
- _spark_echo -n ${ticks[$(( (((n-min)<<8)/f) ))]}
+ _spark_echo -n ${ticks[$(( ((n-min)<<8)/f ))]}
done
_spark_echo
}
}
catnew() {
- local dir file
+ local dir file _
dir="$1"
+ # shellcheck disable=SC2030
inotifywait -m "$dir" -e create -e moved_to | while read -r _ _ file; do
hr
cat "$dir/$file"
prompt-command() {
local return=$? # this MUST COME FIRST
+
# all usable colors:
# black
# green nonzero exit (pri 1)
if [[ $HISTFILE ]]; then
history -a # save history
+ if [[ -e $HOME/.iank-stream-on ]]; then
+ if [[ $HISTFILE == $HOME/.bh ]]; then
+ ps_char="HISTP "
+ fi
+ elif [[ $HISTFILE == /a/bin/data/stream_hist ]]; then
+ ps_char="HISTS "
+ fi
fi
ps_color="$term_purple"
- ps_char='\$'
+ ps_char="$ps_char"'\$'
if [[ ! -O . ]]; then # not owner
if [[ -w . ]]; then # writable
ps_color="$term_bold$term_red"
fi
jobs_char=
if [[ $(jobs -p) ]]; then
- jobs_char='j\j '
+ jobs_char="$(jobs -p)"'j\j '
fi
fi
PS1="${PS1%"${PS1#*[wW]}"} $jobs_char$psudo\[$ps_color\]$ps_char\[$term_nocolor\] "
+
+
# copy of what is automatically added by guix.
# adds [env] to PS1 if GUIX_ENVIRONMENT is set and PS1 contains '$';
if [ -n "$GUIX_ENVIRONMENT" ]; then
# set titlebar. instead, using more advanced
# titelbar below
#echo -ne "$_title_escape $HOSTNAME ${PWD/#$HOME/~} \007"
+
+ if [[ $KONSOLE_VERSION ]]; then
+ # from konsole, output via ctrl-alt-]
+ if [[ ! $PS1 =~ 133 ]] ; then
+ PS1='\[\e]133;L\a\]\[\e]133;D;$?\]\[\e]133;A\a\]'$PS1'\[\e]133;B\a\]' ;
+ PS2='\[\e]133;A\a\]'$PS2'\[\e]133;B\a\]' ;
+ PS0='\[\e]133;C\a\]' ; fi
+ fi
+
}
PROMPT_COMMAND=(prompt-command)
fi
+
+lp22viewers() {
+ v=0
+ roomv=(0 0)
+ rooms=(jupiter saturn)
+ for ip in 209.51.188.25 live.fsf.org; do
+ out=$(curl -sS --insecure https://$ip/)
+ for i in 0 1 2; do
+ room=${rooms[i]}
+ while read -r n; do
+ v=$((v+n))
+ # shellcheck disable=SC2004 # false positive
+ roomv[$i]=$(( ${roomv[$i]} + n ))
+ done < <(printf "%s\n" "$out" | grep -Po "$room.*?current[^0-9]*[0-9]*" | grep -o '[0-9]*$' )
+ done
+ done
+ printf "total: %s " $v
+ for i in 0 1; do
+ room=${rooms[i]}
+ printf "$room: %s " "${roomv[$i]}"
+ done
+ echo
+}
+
+arpflush() {
+ local default_route_dev
+ default_route_dev=$(ip r show default | sed 's/.*dev \([^ ]*\).*/\1/' | head -n1)
+ m s ip n flush dev "$default_route_dev"
+}
+
+dsh() {
+ command dsh -c "$@"
+}
+
+# cat or bat with color if we have it
+v() {
+ if type -t batcat >/dev/null; then
+ # note: another useful useful style is "header"
+ batcat --color always --style plain --theme Coldark-Cold -P "$@"
+ else
+ cat "$@"
+ fi
+}
+
+# Combine files $@ into a single file with comments between them which
+# allow splitting them back with fsplit.
+#
+# Assumes file names do not have newlines in them.
+fcomb() {
+ local f comment out
+ # generated with cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c8
+ comment='# jvvuyUsq '
+ out=~/fcomb
+ rm -f $out
+ for f; do
+ echo "$comment$f" >>$out
+ cat "$f" >>$out
+ done
+}
+fsplit() {
+ local f fin line fin_lines
+ fin=~/fcomb
+ line=1
+ fin_lines=$(wc -l "$fin" | awk '{print $1}')
+ comment='# jvvuyUsq '
+ while (( line <= fin_lines )); do
+ f=$(sed -n "${line}s/^$comment//p" "$fin")
+ sed -n "$line,/^$comment/{/^$comment/d;p}" "$fin" >"$f"
+ line=$(( line + 1 + $(wc -l "$f" | awk '{print $1}') ))
+ done
+}
+
# * stuff that makes sense to be at the end