2 # Copyright (C) 2019 Ian Kelling
3 # SPDX-License-Identifier: AGPL-3.0-or-later
4 # this gets sourced. shebang is just for file mode detection
6 # Use source ~/.bashrc instead of doing bash -l when running a script
7 # so this can set extdebug and avoid the bash debugger.
10 if [[ -s /a
/bin
/bash-bear-trap
/bash-bear
]]; then
11 # shellcheck source=/a/bin/bash-bear-trap/bash-bear
12 source /a
/bin
/bash-bear-trap
/bash-bear
13 # wtf, shellcheck doesn't allow disabling warnings in elifs
15 # bleh shellcheck can't handle disabling in an elif, so nesting this if.
16 # shellcheck disable=SC2154 # set in .bashrc
17 if [[ -s $bashrc_dir/bash-bear
]]; then
18 # shellcheck source=/a/bin/bash-bear-trap/bash-bear
19 source $bashrc_dir/bash-bear
23 # In t8, it runs clear_console for login shells by default. I don't want
24 # my console cleared. And linux ttys get cleared without this.
25 if shopt login_shell
>/dev
/null
&& [[ -e ~
/.bash_logout
]]; then
29 # if [[ -s /usr/share/bash-completion/completions/git ]]; then
30 # source /usr/share/bash-completion/completions/git
32 # if [[ -s /usr/share/bash-completion/completions/gitk ]]; then
33 # source /usr/share/bash-completion/completions/gitk
36 # for testing error catching:
52 # remove all aliases. aliases provided by the system tend to get in the way,
53 # for example, error happens if I try to define a function the same name as an alias
56 # remove gnome keyring warning messages
57 # there is probably a more proper way, but I didnt find any easily on google
58 # now using xfce+xmonad instead of vanilla xmonad, so disabling this
59 #unset GNOME_KEYRING_CONTROL
61 # use extra globing features.
63 # include .files when globbing, but ignore files name . and ..
64 # setting this also sets dotglob.
65 export GLOBIGNORE
="*/.:*/.."
67 # Useful info. see man bash.
71 # broken with bash_completion package. Saw a bug for this once. dont anymore.
72 # still broken in wheezy
73 # still buggered in latest stable from the web, version 2.1
74 # perhaps its fixed in newer git version, which fails to make for me
75 # this note is from 6-2014.
76 # still broken in flidas.
79 # make tab on an empty line do nothing
80 shopt -s no_empty_cmd_completion
82 # fix spelling errors for cd, only in interactive shell
84 # append history instead of overwritting it
86 # for compatibility, per gentoo/debian bashrc
88 # attempt to save multiline single commands as single history entries.
95 if [[ $LC_INSIDE_EMACS ]]; then
96 # EMACS is used by bash on startup, but we dont need it anymore.
97 # plus I hit a bug in a makefile which inherited it
99 export LC_INSIDE_EMACS
102 # scp completion does not work, but this doesnt fix it. todo, figure this out
103 #complete -r scp &> /dev/null
104 # todo, remote file completion fails, figure out how to turn it off
105 export NODE_DISABLE_COLORS
=1
106 # This gets rid of ugly terminal escape chars in node repl
107 # sometime, Id like to have completion working in emacs shell for node
108 # the offending chars can be found in lib/readline.js,
109 # things that do like:
110 # stream.write('\x1b[' + (x + 1) + 'G');
111 # We can remove them and keep readline, for example by doing this
113 #!/usr/bin/env nodejs
114 # var readline = require('readline');
115 # readline.cursorTo = function(a,b,c) {};
116 # readline.clearScreenDown = function(a) {};
117 # const repl = require('repl');
118 # var replServer = repl.start('');
120 # no prompt, or else readline complete seems to be confused, based
121 # on our column being different? node probably needs to send
122 # different kind of escape sequence that is not ugly. Anyways,
123 # completion doesnt work yet even with the ugly prompt, so whatever
125 export NODE_NO_READLINE
=1
129 export SSH_CONFIG_FILE_OVERRIDE
=/root
/.ssh
/confighome
133 # emacs has a different default search path than the info command. This
134 # adds the info defaults to emacs. This is commented because after
135 # various upgrades this is no longer a problem: for the directories that
136 # exist on my system, emacs already includes the ones that info
139 # but not the reverse, because I dun
140 # care much about the cli. The search path is only on the cli if you run
141 # "info xxx", or in emacs if you run '(info xxx)', so not that
142 # important and i don't bother fixing it.
144 # # info info says this path is what was compiled, and its not documented
145 # # anywhere. Through source grepping, i found it in files.h of the info
146 # # source in trisquel flidas.
148 # # Trailing : means for emacs to add its own stuff on to the end.
150 # # A problem with this is that directories which are not readable breaks info. And of course, this hard coding is not nice.
151 # # I removed PATH from the start, because I've never seen an info file in PATH. And removed ".", because I can just specify the full file name in that case.
153 # # https://raw.githubusercontent.com/debian-tex/texinfo/master/info/filesys.h
156 # # note: to split up the var like this, do:
157 # # IFS=:; printf '%s\n' $INFOPATH
162 # /usr/local/lib/info
164 # /usr/local/gnu/info
165 # /usr/local/gnu/lib/info
170 # /usr/share/lib/info
171 # /usr/local/share/info
172 # /usr/local/share/lib/info
173 # /usr/gnu/lib/emacs/info
174 # /usr/local/gnu/lib/emacs/info
175 # /usr/local/lib/emacs/info
176 # /usr/local/emacs/info
179 # for d in ${dirs[@]}; do
180 # if [[ -r $d ]]; then
181 # INFOPATH="$d:$INFOPATH"
187 # note: guix bash config does this automatically.
188 if [[ $INFOPATH != *: ]]; then
189 INFOPATH
="$INFOPATH:"
192 # info parameter expansion
196 # / search, {, }: next/prev match
197 # ctrl/alt-v scroll forward/backward within this node
198 # l: go to previous node
201 info bash
'Basic Shell Features' 'Shell Expansions' 'Shell Parameter Expansion'
205 # for openwrt system that has no stty, this is easier than
206 # guarding every time i use it.
207 if ! type -p stty
>/dev
/null
; then
213 if [[ $
- == *i
* ]]; then
214 # for readline-complete.el
215 if [[ $LC_INSIDE_EMACS ]]; then
216 # all for readline-complete.el
218 bind 'set horizontal-scroll-mode on'
219 bind 'set print-completions-horizontally on'
220 bind '"\C-i": self-insert'
224 if [[ $TERM != dumb
]] && test -t 1; then
228 if [[ $KONSOLE_PROFILE_NAME ]]; then
232 if [[ $TERM == alacritty
&& ! -e /usr
/share
/terminfo
/a
/alacritty
]]; then
233 # todo: we should try installing the alacritty terminfo if it is not found
234 # https://github.com/alacritty/alacritty/issues/2838
238 # copying from the alacritty example above,
239 if [[ $TERM == xterm-kitty
]]; then
240 if [[ ! -e /usr
/share
/terminfo
/x
/xterm-kitty
]]; then
243 if [[ -e /a
/opt
/kitty
/shell-integration
/bash
/kitty.bash
]]; then
244 KITTY_SHELL_INTEGRATION
=t
245 source /a
/opt
/kitty
/shell-integration
/bash
/kitty.bash
250 # todo: not sure this works in sakura
252 #bind "\C-w": kill-region
253 # sakura == xterm-256color
255 if [[ $TERM != xterm-kitty
&& $TERM == xterm
* ]]; then
256 # control + arrow keys. for other terminals, see http://unix.stackexchange.com/questions/10806/how-to-change-previous-next-word-shortcut-in-bash
257 bind '"\e[1;5C": shell-forward-word' 2>/dev
/null
258 bind '"\e[1;5D": shell-backward-word' 2>/dev
/null
260 # make ctrl-backspace work. for konsole, i fixed it through
261 # /home/iank/.local/share/konsole/default.keytab
263 bind '"\eOc": shell-forward-word'
264 bind '"\eOd": shell-backward-word'
266 # i cant remember why i did this, probably to free up some keys to bind
267 # to other things in bash.
268 # other than C-c and C-z, the rest defined by stty -a are, at least in
269 # gnome-terminal, overridden by bash, or disabled by the system
270 stty lnext undef stop undef start undef
276 # fixup broken backspace in chroots
277 xterm-kitty|alacritty
)
279 TERM
=xterm-256color
command chroot
"$@"
284 export BC_LINE_LENGTH
=0
287 export PROFILE_TASKS_TASK_OUTPUT_LIMIT
=100
289 # note, if I use a machine I dont want files readable by all users, set
290 # umask 077 # If fewer than 4 digits are entered, leading zeros are assumed
292 # i for insensitive. the rest from
293 # X means dont remove the current screenworth of output upon exit
294 # R means to show colors n things
295 # a useful flag is -F aka --quit-if-one-screen
297 export SYSTEMD_LESS
=$LESS
299 export NNN_COLORS
=2136
301 export SL_FILES_DIR
=/b
/ds
/sl
/.iank
302 export SL_INFO_DIR
=/p
/sshinfo
307 # this is adapted from things printed to term after install
308 # pyenv. commented for now since I'm not actually using pyenv.
310 # export PYENV_ROOT="$HOME/.pyenv"
311 # command -v pyenv &>/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"
312 # command -v pyenv &>/dev/null && eval "$(pyenv init -)"
315 # output showed this example for pyenv-virtualenv, which i have no idea
316 # what it is, but leaving it as a comment in case I end up doing python
319 #eval "$(pyenv virtualenv-init -)"
320 ### end begin pyenv ###
326 if [[ -s $bashrc_dir/path-add-function
]]; then
327 source $bashrc_dir/path-add-function
328 if [[ $SSH_CLIENT ]]; then
329 if grep -qF /home
/iank
/.iank
/e
/e
/etc
/exports
&>/dev
/null
; then
330 export EMACSDIR
=/home
/iank
/.iank
/e
/e
336 # if someone exported $SOE (stop on error), catch errors.
338 # Note, on debian this results in the following warning when in ssh,
339 # hich I haven't figured out how to fix. It doesn't happen if we source
340 # after the shell has started
342 # bash: /usr/share/bashdb/bashdb-main.inc: No such file or directory
343 # bash: warning: cannot start debugger; debugging mode disabled
345 if [[ -e /a
/bin
/bash-bear-trap
/bash-bear
]]; then
346 source /a
/bin
/bash-bear-trap
/bash-bear
356 if [[ -s $path ]]; then
357 # shellcheck disable=SC1090 # this is dynamic, shellcheck can't follow it.
359 elif [[ -s $bashrc_dir/$file ]]; then
360 # shellcheck disable=SC1090 # this is dynamic, shellcheck can't follow it.
361 source $bashrc_dir/$file
366 mysrc
/a
/bin
/small-misc-bash
/ll-function
367 mysrc
/a
/bin
/distro-functions
/src
/package-manager-abstractions
369 # things to remember:
370 # ALT-C - cd into the selected directory
371 # CTRL-T - Paste the selected file path into the command line
373 # good guide to some of its basic features is the readme file
374 # https://github.com/junegunn/fzf
376 # if [[ -s /usr/share/doc/fzf/examples/key-bindings.bash ]]; then
377 # source /usr/share/doc/fzf/examples/key-bindings.bash
383 # temporary functions
385 m
"${@//spring/fall}"
388 e
"${@//spring/fall}"
392 ### begin FSF section ###
394 # Comments before functions are meant to be good useful
395 # documentation. If they fail at that, please improve them or send Ian a
398 ## copy bash completion
400 # It copies how the bash completion works from one command to other
401 # commands. Generally just use within a .bashrc.
403 # Usage: ORIGINAL_COMMAND TARGET_COMMAND...
409 if ! c
=$
(complete
-p $src 2>/dev
/null
); then
410 _completion_loader
$src &>/dev
/null ||
:
411 c
=$
(complete
-p $src 2>/dev
/null
) ||
return 0
419 ## BEGIN functions to change directory better than cd ##
423 # c: acts like cd, but stores directory history: you could alias to cd if you wanted.
426 # cl: list recent directories and optionally choose one.
428 # Finer details you may want to skip:
430 # bl: print the list of back and forward directories.
432 # We keep 2 stacks of directories, forward and back. Unlike with a web
433 # browser, the forward stack is not erased when going somewhere new.
435 # Recent directories are stored in ~/.cdirs.
437 declare -a _dir_forward _dir_back
439 # normally, the top of _dir_back is our current dir. if it isn't,
440 # put it on there, except we don't want to do that when we
441 # just launched a shell
442 if [[ $OLDPWD ]]; then
443 if (( ${#_dir_back[@]} == 0 )) ||
[[ ${_dir_back[-1]} != "$PWD" ]]; then
448 if (( ${#_dir_back[@]} == 0 )) ||
[[ ${_dir_back[-1]} != "$PWD" ]]; then
451 echo "$PWD" >> ~
/.cdirs
458 if (( ${#_dir_back[@]} == 0 )); then
459 echo "nothing left to go back to" >&2
462 top_back
="${_dir_back[-1]}"
464 if [[ $top_back == "$PWD" ]] && (( ${#_dir_back[@]} == 1 )); then
465 echo "already on last back entry" >&2
470 if [[ $top_back == "$PWD" ]]; then
471 # add to dirf if not already there
472 if (( ${#_dir_forward[@]} == 0 )) ||
[[ ${_dir_forward[-1]} != "$top_back" ]]; then
473 _dir_forward
+=("$top_back")
475 unset "_dir_back[-1]"
476 command cd "${_dir_back[-1]}"
478 if (( ${#_dir_forward[@]} == 0 )) ||
[[ ${_dir_forward[-1]} != "$PWD" ]]; then
479 _dir_forward
+=("$PWD")
481 command cd "$top_back"
484 # Interesting feature, not sure I want it.
485 # give us a peek at what is next in the list
486 # if (( ${#_dir_back[@]} >= 2 )); then
487 # printf "%s\n" "${_dir_back[-2]}"
491 # c/b/f Implementation notes:
493 # The top of the back is $PWD
494 # as long as the last directory change was due to c,b,or cl.
496 # Example of stack changes:
522 if (( ${#_dir_forward[@]} == 0 )); then
523 echo "no forward dir left" >&2
526 top_forward
="${_dir_forward[-1]}"
527 unset "_dir_forward[-1]"
530 # give us a peek at what is next in the list
531 # if (( ${#_dir_forward[@]} )); then
532 # printf "%s\n" "${_dir_forward[-1]}"
537 local i line input start
538 local -A buttondirs alines
539 local -a buttons
dirs lines
540 buttons
=( {a..z
} {2.
.9} )
541 if [[ ! -s ~
/.cdirs
]]; then
542 echo nothing
in ~
/.cdirs
548 mapfile
-t lines
<~
/.cdirs
549 start
=$
(( ${#lines[@]} - 1 ))
551 # we have ~33 buttons as of this writing, so lets
552 # prune down the history every once in a while.
553 if (( start
> 500 )); then
554 tac ~
/.cdirs |
awk '!seen[$0]++' |
head -n 200 |
tac | sponge ~
/.cdirs ||
[[ $?
== 141 ]]
557 for (( j
=start
; j
>= 0; j--
)); do
559 if [[ ! $line ||
${alines[$line]} ||
! -d "$line" ||
$line == "$PWD" || line
== "$HOME" ]]; then
563 buttondirs
[${buttons[i]}]="$line"
564 printf "%s %s\n" ${buttons[i]} "$line"
565 # the LINES bit is for when we have a short terminal, just dont print all
566 # the directories. alternative would be to do something like less the list.
567 if (( i
== ${#buttons[@]} - 1 )) ||
{ [[ $LINES ]] && (( i
== LINES
- 3 )); }; then
573 if (( i
== 0 )); then
574 echo "no dirs in ~/.cdirs"
578 if [[ $input != $
'\n' ]]; then
579 c
"${buttondirs[$input]}"
582 # bl = back list. lists the back and forward directories. i tend to
583 # forget this exists and use cl instead.
587 start
=$
(( ${#_dir_back[@]} - 1 ))
589 # cleanup possible repeating of pwd
590 if (( start
>= 0 )) && [[ ${_dir_back[$start]} == "$PWD" ]]; then
591 start
=$
(( start
- 1 ))
594 if (( start
>= 0 )); then
595 for (( i
=start
; i
>= 0 ; i--
)); do
596 printf "%s %s\n" $j ${_dir_back[i]}
598 if (( j
>= max
)); then
605 start
=$
(( ${#_dir_forward[@]} - 1 ))
607 # cleanup possible repeating of pwd
608 if (( start
>= 0 )) && [[ ${_dir_forward[$start]} == "$PWD" ]]; then
609 start
=$
(( start
- 1 ))
611 if (( start
< 0 )); then
616 for (( i
=start
; i
>= 0 ; i--
)); do
617 printf "%s %s\n" $j ${_dir_forward[i]}
619 if (( j
>= max
)); then
624 # like running cl <enter> a <enter>
627 mapfile
-t lines
<~
/.cdirs
628 start
=$
(( ${#lines[@]} - 1 ))
629 for (( j
=start
; j
>= 0; j--
)); do
631 if [[ ! $line ||
! -d "$line" ||
$line == "$PWD" || line
== "$HOME" ]]; then
639 ## END functions to change directory better than cd ##
641 # pee do. run args as a command with output copied to syslog.
643 # Usage: pd [-t TAG] COMMAND...
645 # -t TAG Override the tag in the syslog. The default is COMMAND with
646 # any path part is removed, eg. for /bin/cat the tag is cat.
648 # You can view the log via "journalctl -t TAG"
654 -t) tag
="$2"; shift 2 ;;
656 echo "PWD=$PWD command: $*" | logger
-t $tag
657 "$@" |
& pee
cat "logger -t $tag" || ret
=$?
658 echo "exited with status=$ret" | pee
cat "logger -t $tag"
659 # this avoids any err-catch
660 (( ret
== 0 )) ||
return $ret
664 # jdo = journal do. Run command as transient systemd service, tailing
665 # its output in the journal until it completes.
667 # Usage: jdo COMMAND...
669 # Compared to pd: commands recognize this is a non-interactive shell.
670 # The service is unaffected if our ssh connection dies, no need to run
673 # Note: The last few lines of any existing entries for a unit by that
674 # name will be output first, and there will be a few second delay at the
675 # start of the command, and a second or so at the end.
677 # Note: Functions and aliases obviously won't work, we resolve the
680 # Note: requires running as root.
682 local cmd cmd_name jr_pid ret
686 if [[ $EUID != 0 ]]; then
687 echo "jdo: error: rerun as root"
691 if [[ $cmd != /* ]]; then
692 cmd
=$
(type -P "$cmd")
695 journalctl
-qn2 -f -u "$cmd_name" &
696 # Trial and error of time needed to avoid missing initial lines.
697 # .5 was not reliable. 1 was not reliable. 2 was not reliable
700 systemd-run
--unit "$cmd_name" --wait --collect "$cmd" "$@" || ret
=$?
701 # The sleep lets the journal output its last line
702 # before the prompt comes up.
704 kill $jr_pid &>/dev
/null ||
:
707 # this avoids any err-catch
708 (( ret
== 0 )) ||
return $ret
712 # standard date as used in logs
717 # date in log appropriate format
724 command ts
"%F %T" "$@"
727 # ts log. log command to log file.
728 # usage: tsl LOG_PATH_PREFIX COMMAND...
729 # example: tsl /root/command
730 # log file will be like /root/command-2024-02-10.log
732 local log_prefix log_path appending ret
733 if (( $# < 2 )); then
734 echo "tsl: error: expected >= 2 arguments, got $#" >&2
738 if [[ $log_prefix == */* && ! -d ${log_prefix%*/} ]]; then
739 echo "tsl: error: expected directory at ${log_prefix%*/}" >&2
742 log_path
=$log_prefix-$
(date +%Y-
%m-
%d
).log
744 if [[ -s $log_path ]]; then
748 printf "%s\n" "CWD: $PWD, log: $log_path, running $*" | ts
"%F %T" |
tee -a "$log_path"
750 "$@" |
& ts
"%F %T" |
tee -a "$log_path" || ret
=$?
751 printf "%s\n" "exit code $ret from command: $*" | ts
"%F %T" |
tee -a "$log_path"
753 printf "%s\n" "note: this log file contains logs before those of previous command" | ts
"%F %T" |
tee -a "$log_path"
759 mapfile
-t cmds
<<'EOF'
760 tail -n +1 /proc/mdstat /etc/mdadm/mdadm.conf /etc/fstab /etc/crypttab
763 ls -la /dev/disk/by-id
766 for cmd
in "${cmds[@]}"; do
786 ....
() { c ..
/..
/..
; }
787 .....
() { c ..
/..
/..
/..
; }
788 ......
() { c ..
/..
/..
/..
/..
; }
793 path
=$
(readlink
-e "$f")
794 echo "cat >$path <<'EOF'"
801 # file cut copy and paste, like the text buffers :)
802 # I havnt tested these.
803 _fbufferinit
() { # internal use
804 ! [[ $my_f_tempdir ]] && my_f_tempdir
="$(mktemp -d)"
805 rm -rf "${my_f_tempdir:?}"/*
809 cp "$@" "$my_f_tempdir"/
813 mv "$@" "$my_f_tempdir"/
815 fpst
() { # file paste
816 [[ $2 ]] && { echo too many arguments
; return 1; }
818 cp "$my_f_tempdir"/* "$target"
822 local host ip port
file key tmp
823 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" ||
: )
824 file=$
(readlink
-f ~
/.ssh
/known_hosts
)
826 echo "khfix: ssh failed"
829 if [[ $port != 22 ]]; then
830 ip_entry
="[$ip]:$port"
831 host_entry
="[$host]:$port"
836 if [[ $host != "$ip" ]]; then
838 ssh-keygen
-F "$host_entry" -f $file >$tmp ||
[[ $?
== 1 ]] # 1 when it doesnt exist in the file
839 if [[ -s $tmp ]]; then
840 key
=$
(sed -r 's/^.*([^ ]+ +[^ ]+) *$/\1/' $tmp)
844 grep -Fv "$key" "$file" | sponge
"$file"
849 ssh-keygen
-F "$ip_entry" -f $file >$tmp ||
[[ $?
== 1 ]]
850 if [[ -s $tmp ]]; then
851 key
=$
(sed -r 's/^.*([^ ]+ +[^ ]+) *$/\1/' $tmp)
855 grep -Fv "$key" "$file" | sponge
"$file"
857 ll ~
/.ssh
/known_hosts
859 khfix-r
() { # known hosts fix + root
860 _khfix-common
"$@" ||
return 1
865 _khfix-common
"$@" ||
return 1
869 # copy path into clipboard
872 x
=$
(readlink
-nf "${1:-$PWD}")
873 # yes, its kinda dumb that xclip/xsel cant do this in one invocation
874 echo -n "$x" | xclip
-selection clipboard
878 # a1 = awk {print $1}
879 for field
in {1.
.20}; do
880 eval a
$field"() { awk '{print \$$field}'; }"
883 for num
in {1.
.9}; do
884 eval h
$num"() { head -n$num || [[ \$? == 141 ]]; }"
889 # shellcheck disable=SC2046 disable=SC2001 disable=SC2183 # hacks, expected
890 printf '%d.%d.%d.%d\n' $
(echo $1 |
sed 's/../0x& /g')
894 local f out outdir
in fname origdir skip1
898 while [[ $1 == -* ]]; do
900 # if we got interrupted after 1st phase
912 # first pass only uses about 1 cpu, so run in parallel
916 if [[ $f == /* ]]; then
921 out
="$origdir/$outdir/$fname"
922 mkdir
-p /tmp
/vp
9/$fname
924 if ! $skip1 && [[ ! -s ffmpeg2pass-0.log
]]; then
925 # -nostdin or else wait causes ffmpeg to go into stopped state. dunno why, random stackoverflow answer.
926 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
928 if [[ -e $out ]]; then rm -f $out; fi
929 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
936 utcl
() { # utc 24 hour time to local hour 24 hour time
937 echo "print( ($1 $(date +%z | sed -r 's/..$//;s/^(-?)0*/\1/')) % 24)"|python3
945 # for running in a fai rescue. iank specific.
947 d
=vgata-Samsung_SSD_850_EVO_2TB_S2RLNX0J502123D
948 for f
in $d vgata-Samsung_SSD_870_QVO_8TB_S5VUNG0N900656V
; do
949 cryptsetup luksOpen
--key-file /p
/dev
/$f/root crypt-
$f-root
950 cryptsetup luksOpen
--key-file /p
/dev
/$f/o crypt-
$f-o
952 mount
-o subvol
=root_trisquelaramo
/dev
/mapper
/crypt-
$d-root /mnt
953 mount
-o subvol
=a
/dev
/mapper
/crypt-
$d-root /mnt
/a
954 mount
-o subvol
=o
/dev
/mapper
/crypt-
$d-o /mnt
/o
955 mount
-o subvol
=boot_trisquelaramo
/dev
/sda2
/mnt
/boot
963 c4
() { c
/var
/log
/exim4
; }
965 caa
() { git commit
--amend --no-edit -a; }
978 find -L "$@" -type f
-not \
( -name .svn
-prune -o -name .git
-prune \
979 -o -name .hg
-prune -o -name .editor-backups
-prune \
980 -o -name .undo-tree-history
-prune \
) -printf '%h\0%d\0%p\n' |
sort -t '\0' -n \
981 |
awk -F '\0' '{print $3}' 2>/dev
/null |
while read -r file; do
983 printf "%s\n" "$file"
990 calc
() { echo "scale=3; $*" |
bc -l; }
991 # no having to type quotes, but also no command history:
995 echo "scale=3; $x" |
bc -l
1006 ccat
() { # config cat. see a config without extra lines.
1007 sed -r '/^[[:space:]]*([;#]|--|\/\/|$)/d' "$@"
1013 # dev/pts needed for pacman signature check
1014 for d
in dev proc sys dev
/pts
; do
1016 if ! mountpoint
$d &>/dev
/null
; then
1017 m s mount
-o bind /$d $d
1023 # dev/pts needed for pacman signature check
1024 for d
in dev
/pts dev proc sys
; do
1026 if mountpoint
$d &>/dev
/null
; then
1034 # join options which are continued to multiples lines onto one line
1036 while IFS
= read -r line
; do
1037 # remove leading spaces/tabs. assumes extglob
1038 if [[ $line == "[ ]*" ]]; then
1039 line
="${line##+( )}"
1044 elif [[ $line == *=* ]]; then
1045 echo "$pastline" >> "$2"
1048 pastline
="$pastline $line"
1050 done < <(grep -vE '^([ \t]*#|^[ \t]*$)' "$1")
1051 echo "$pastline" >> "$2"
1055 # diff config files,
1056 # setup for format of postfix, eg:
1059 local pastline unified f1 f2
1063 _cdiff-prep
"$1" "$f1"
1064 _cdiff-prep
"$2" "$f2"
1065 cat "$f1" "$f2" |
grep -Po '^[^=]+=' |
sort |
uniq > "$unified"
1066 while IFS
= read -r line
; do
1067 # the default bright red / blue doesnt work in emacs shell
1068 dwdiff
-cblue,red
-A best
-d " ," <(grep "^$line" "$f1" ||
echo ) <(grep "^$line" "$f2" ||
echo ) | colordiff
1074 local start
=$SECONDS
1076 # shellcheck disable=SC2030
1077 inotifywait
-m "$dir" -e create
-e moved_to | \
1078 while read -r filedir _
file; do
1081 calc $
((SECONDS
- start
)) / 60
1088 s chown
-R $USER:$USER "$@"
1091 # shellcheck disable=SC2032
1093 # makes it so chown -R symlink affects the symlink and its target.
1094 if [[ $1 == -R ]]; then
1096 command chown
-h "$@"
1097 command chown
-R "$@"
1108 d
() { builtin bg "$@"; }
1111 # f would be more natural, but i already am using it for something
1112 z
() { builtin fg "$@"; }
1115 x
() { builtin kill %%; }
1118 diff --strip-trailing-cr -w "$@" # diff content
1126 safe_rename
"$x" "$y"
1131 # usage: dfp MOUNTPOINT [SECOND_INTERVAL]
1132 # SECOND_INTERVAL defaults to 90
1135 local a b mp interval
1138 if [[ ! $mp ]]; then
1139 echo "dfp: error, missing 1st arg" >&2
1143 a
=$
(df
--output=used
$mp |
tail -n1)
1145 b
=$
(df
--output=used
$mp |
tail -n1)
1146 printf "used mib: %'d mib/min: %s\n" $
(( b
/1000 )) $
(( (b-a
) / (interval
* 1000 / 60 ) ))
1150 # get ipv4 ip from HOST. or if it is already a number, return that
1158 getent ahostsv4
"$host" |
awk '{ print $1 }' |
head -n1
1164 command dig +nostats
+nocmd
"$@"
1166 # Output with sections sorted, and removal of query id, so 2 dig outputs can be diffed.
1170 dig +nordflag
"$@" |
sed -r 's/^(;; ->>HEADER<<-.*), id: .*/\1/' |
while read -r l
; do
1171 if [[ $l == [^\
;]* ]]; then
1175 printf "%s" "$sec" |
sort
1183 # compare digs to the 2 servers
1184 # usage: digdiff @server1 @server2 DIG_ARGS
1185 # note: only the soa master nameserver will respond with
1186 # ra "recursive answer" flag. That difference is meaningless afaik.
1193 digsort
$s1 "$@" |
tee /tmp
/digdiff
1194 diff -u /tmp
/digdiff
<(digsort
$s2 "$@")
1197 # date in a format i like reading
1199 date "+%A, %B %d, %r" "$@"
1204 # date with all digits in a format i like
1208 ccomp
date dt dtr dtd
1210 dus
() { # du, sorted, default arg of
1211 du
-sh ${@:-*} |
sort -h
1216 e
() { printf "%s\n" "$*"; }
1224 printf "%qEOL\n" "${arg}"
1225 printf "%s" "${arg}" |
& hexdump -C
1229 # echo variables. print var including escapes, etc, like xxd for variable
1235 if [[ -v $arg ]]; then
1236 printf "%qEOL\n" "${!arg}"
1237 printf "%s" "${!arg}" |
& hexdump -C
1239 echo arg
$arg is
unset
1245 [[ ${#@} == 2 ]] ||
{ echo "error: ediff requires 2 arguments"; return 1; }
1246 emacs
--eval "(ediff-files \"$1\" \"$2\")"
1250 # shellcheck disable=SC2120 # we expect to pass arguments in use outside this file
1253 tail -F /var
/log
/exim
4/mainlog
/var
/log
/exim
4/*main
/var
/log
/exim
4/paniclog
/var
/log
/exim
4/*panic
-n 200 "$@"
1257 tail -F /var
/log
/exim
4/mainlog
-n 200 "$@"
1260 tail -F /var
/log
/exim
4/mymain
-n 200 "$@"
1262 ccomp
tail etail etail2
1264 # ran into this online, trying it out
1266 ( "$@" &>/dev
/null
& disown )
1270 ssh "$@" cat .ssh
/authorized_keys
{,2}
1274 # print exim old pids
1276 local configtime pid piduptime now daemonpid
1277 printf -v now
'%(%s)T' -1
1278 configtime
=$
(stat
-c%Y
/var
/lib
/exim
4/config.autogenerated
)
1279 if [[ -s /run
/exim
4/exim.pid
]]; then
1280 daemonpid
=$
(cat /run
/exim
4/exim.pid
)
1282 for pid
in $
(pgrep
-f '^/usr/sbin/exim4( |$)'); do
1283 # the daemonpid gets reexeced on HUP (service reloads), keeping its same old timestamp
1284 if [[ $pid == "$daemonpid" ]]; then
1287 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
1288 if (( configtime
> now
- piduptime
)); then
1294 # exim tail but only watch lines from new pids
1297 for pid
in $
(eoldpids
); do
1300 if [[ $oldpids ]]; then
1301 etail |
awk '$3 !~ /^\[('"${oldpids%|}"')\]$/'
1306 # exim watch as old pids go away
1308 local configtime pid piduptime now tmpstr
1314 mapfile
-t oldpids
<<<"$tmpstr"
1315 if (( ! ${#oldpids[@]} )); then
1318 # print the date every 20 iterations
1319 if (( ! count
% 20 )); then
1323 ps
-f -p "${oldpids[*]}"
1329 less /var
/log
/exim
4/mainlog
1333 exiqgrep
-ir.\
* -o 60 |
while read -r i
; do
1336 hlm exigrep
$i /var
/log
/exim
4/mainlog |
cat ||
:
1340 # other ways to get the list of message ids:
1341 # exim -bp | awk 'NF == 4 {print $3}'
1342 # # this is slower 160ms, vs 60.
1344 exiqgrep
-ir.\
* |
xargs exim
-Mrm
1349 mkdir
-p /tmp
/edev
/etc
1350 cp -ra /etc
/exim4
/tmp
/edev
/etc
1351 cp -ra /etc
/alias* /tmp
/edev
/etc
1352 find /tmp
/edev
/etc
/exim4
-type f
-execdir sed -i "s,/etc/,/tmp/edev/etc/,g" '{}' +
1356 update-exim4.conf
-d /tmp
/edev
/etc
/exim4
-o /tmp
/edev
/e.conf
1360 # show important information about incoming mail in the exim log
1362 sed -rn '/testignore|jtuttle|eximbackup/!s/^[^ ]+ ([^ ]+) [^ ]+ [^ ]+ <= ([^ ]+).*T="(.*)" from (<[^ ]+> .*$)/\1 \4\n \3/p' <${1:-/var/log/exim4/mainlog}
1365 # 2nd line is message-id:
1367 sed -rn '/testignore|jtuttle|eximbackup/!s/^[^ ]+ ([^ ]+) [^ ]+ [^ ]+ <= ([^ ]+).* id=([^ ]+) T="(.*)" from (<[^ ]+> .*$)/\1 \5\n \3\n \4/p' <${1:-/var/log/exim4/mainlog}
1370 tail -F /var
/log
/exim
4/mainlog |
sed -rn '/testignore|jtuttle|eximbackup/!s/^[^ ]+ ([^ ]+) [^ ]+ [^ ]+ <= ([^ ]+).*T="(.*)" from (<[^ ]+> .*$)/\1 \4\n \3/p'
1377 # find array. make an array of file names found by find into $x
1378 # argument: find arguments
1379 # return: find results in an array $x
1380 while read -rd ''; do
1382 done < <(find "$@" -print0);
1385 faf
() { # find all files. use -L to follow symlinks
1386 find "$@" -not \
( -name .svn
-prune -o -name .git
-prune \
1387 -o -name .hg
-prune -o -name .editor-backups
-prune \
1388 -o -name .undo-tree-history
-prune \
) -type f
2>/dev
/null
1391 # usage ffconcat FILES_TO_CONCAT OUTPUT_FILE
1395 printf "file '%s'\n" "$1" >$tmpf
1396 while (( $# > 1 )); do
1398 printf "file '%s'\n" "$1" >>$tmpf
1400 # https://trac.ffmpeg.org/wiki/Concatenate
1401 ffmpeg
-f concat
-safe 0 -i $tmpf -c copy
"$1"
1406 if (( $# == 0 )); then
1407 echo ffremux error expected args
>&2
1412 tmpf
=$tmpd/"${f##*/}"
1413 ffmpeg
-i "$f" -c:v copy
-c:a copy
$tmpf
1421 # absolute path of file/dir without resolving symlinks.
1423 # Most of the time, I want this where I would normally use readlink.
1424 # This is what realpath -s does in most cases, but sometimes it
1425 # actually resolves symlinks, at least when they are in /.
1427 # Note, if run on a dir, if the final component is relative, it won't
1428 # resolve that. Use the below fpd for that.
1430 # note: we could make a variation of this which
1431 # assigns to a variable name using eval, so that we don't have to do
1432 # x=$(fp somepath), which might save subshell overhead and look nice,
1433 # but I'm not going to bother.
1435 local initial_oldpwd initial_pwd dir base
1436 initial_oldpwd
="$OLDPWD"
1438 if [[ $1 == */* ]]; then
1441 # CDPATH because having it set will cause cd to possibly print output
1443 printf "%s%s\n" "$PWD" "$base"
1444 CDPATH
='' cd "$initial_pwd"
1445 OLDPWD
="$initial_oldpwd"
1447 printf "%s/%s\n" "$PWD" "$1"
1450 # full path of directory without resolving symlinks
1452 local initial_oldpwd initial_pwd dir
1453 initial_oldpwd
="$OLDPWD"
1457 printf "%s%s\n" "$PWD" "$base"
1459 OLDPWD
="$initial_oldpwd"
1466 sudo mailq |gr frozen|
awk '{print $3}' |
while read -r id
; do
1472 echo -e '\n\n##############################\n'
1473 done |
tee -a /tmp
/frozen
1477 while read -r line
; do
1478 printf '%s\n' "$line"
1479 ids
+=("$(printf '%s\n' "$line" |gr frozen|awk '{print $3}')")
1481 echo "sleeping for 2 in case you change your mind"
1483 sudo exim
-Mrm "${ids[@]}"
1487 # like -e for functions. returns on error.
1488 # at the end of the function, disable with:
1490 trap 'echo "${BASH_COMMAND:+BASH_COMMAND=\"$BASH_COMMAND\" }
1491 ${FUNCNAME:+FUNCNAME=\"$FUNCNAME\" }${LINENO:+LINENO=\"$LINENO\" }\$?=$?"
1497 local help="Usage: getdir [--help] PATH
1498 Output the directory of PATH, or just PATH if it is a directory."
1499 if [[ $1 == --help ]]; then
1503 if [[ $# -ne 1 ]]; then
1504 echo "getdir error: expected 1 argument, got $#"
1507 if [[ -d $1 ]]; then
1511 dir
="$(dirname "$1")"
1512 if [[ -d $dir ]]; then
1515 echo "getdir error: directory does not exist"
1521 git_empty_branch
() { # start an empty git branch. carefull, it deletes untracked files.
1522 [[ $# == 1 ]] ||
{ echo 'need a branch name!'; return 1;}
1524 root
=$
(gitroot
) ||
return 1 # function to set gitroot
1526 git symbolic-ref HEAD refs
/heads
/$1
1531 # shellcheck disable=SC2120
1533 local help="Usage: gitroot [--help]
1534 Print the full path to the root of the current git repo
1536 Handles being within a .git directory, unlike git rev-parse --show-toplevel,
1537 and works in older versions of git which did not have that."
1538 if [[ $1 == --help ]]; then
1543 p
=$
(git rev-parse
--git-dir) ||
{ echo "error: not in a git repo" ; return 1; }
1544 [[ $p != /* ]] && p
=$PWD
1550 local args gdb
=false
1552 if [[ $EMACSDIR ]]; then
1553 path-add
"$EMACSDIR/lib-src" "$EMACSDIR/src"
1556 if [[ $DISPLAY ]]; then
1560 if (( $# == 0 )); then
1563 # duplicate -c, but oh well
1564 if ! pgrep
-u $EUID emacsclient
; then
1565 if (( $# == 0 )) && type -p gdb
&>/dev
/null
; then
1571 if [[ $EMACSDIR ]]; then
1573 # todo: we don't have to alter HOME since emacs 29+, we can set
1574 # user-emacs-directory with the flag --init-directory
1576 # Alter the path here, otherwise the nfs mount gets triggered on the
1577 # first path lookup when emacs is not being used.
1578 # shellcheck disable=SC2098 disable=SC2097 # false positive
1579 PATH
="$EMACSDIR/lib-src:$EMACSDIR/src:$PATH" EHOME
=$HOME HOME
=$EMACSDIR m emacsclient
-a "" $args "$@"
1582 # due to a bug, we cant debug from the start unless we get a new gdb
1583 # https://sourceware.org/bugzilla/show_bug.cgi?id=24454
1584 # m gdb -ex="set follow-fork-mode child" -ex=r -ex=quit --args emacs --daemon
1585 m emacsclient
-a "" $args "$@"
1587 cd "/a/opt/emacs-$(distro-name)$(distro-num)"
1588 s gdb
-p "$(pgrep -f 'emacs --daemon')" -ex c
1591 m emacsclient
-a "" $args "$@"
1596 # g pipe. like: cmd | emacs. save cmd output to tmp file, then edit.
1602 #like cmd &> tempfile; emacs tempfile
1604 # note: a useful workflow for doing mass replace on my files:
1606 ## remove any false positives, or manually edit them. rename files if needed.
1607 # sedi 's/REGEX/REPLACEMENT/' $(gr '^/' /a/tmp/gtmp)
1612 # g command substitution
1617 # force terminal version
1623 # quit will prompt if the program crashes.
1624 gdb
-ex=r
-ex=quit
--args emacs
"$@"; r
;
1628 # kill the emacs daemon
1633 grep -iIP --color=auto
"$@" ||
return $?
1635 grr
() { # grep recursive
1636 # Don't return 1 on nonmatch because this is meant to be
1637 # interactive, not in a conditional.
1638 if [[ ${#@} == 1 ]]; then
1639 grep --exclude-dir='*.emacs.d' --exclude-dir='*.git' -riIP --color=auto
"$@" . ||
[[ $?
== 1 ]]
1641 grep --exclude-dir='*.emacs.d' --exclude-dir='*.git' -riIP --color=auto
"$@" ||
[[ $?
== 1 ]]
1649 # recursive everything. search for files/dirs and lines. rs = easy chars to press
1653 find "$@" -not \
( -name .svn
-prune -o -name .git
-prune \
1654 -o -name .hg
-prune -o -name .editor-backups
-prune \
1655 -o -name .undo-tree-history
-prune \
) 2>/dev
/null |
grep -iP --color=auto
"$query"
1659 # horizontal row. used to break up output
1662 # 180 is long enough.
1663 blocks
=██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
1664 printf "%s\n" "$(tput setaf 5 2>/dev/null ||:)${blocks:0:${COLUMNS:-180}}$(tput sgr0 2>/dev/null||:)"
1668 local col input_len
=0
1670 input_len
=$
((input_len
+ 1 + ${#arg}))
1672 col=$
((60 - input_len
))
1673 printf "\e[1;97;41m%s" "$*"
1674 if (( col > 0 )); then
1675 # shellcheck disable=SC2046 # needed to work as intended. a better way would be like hr above.
1676 printf "\e[1;97;41m \e[0m%.0s" $
(eval echo "{1..${col}}")
1680 hlm
() { hl
"$*"; "$@"; }
1682 hrcat
() { local f
; for f
; do [[ -f $f ]] ||
continue; hr
; echo "$f"; cat "$f"; done }
1685 # github-release-dl restic/restic restic_ _linux_amd64.bz2
1687 # https://github.com/restic/restic/releases/download/v0.16.3/restic_0.16.3_linux_amd64.bz2
1688 github-release-dl
() {
1689 local github_path file_prefix file_suffix latest_prefix version redir_path
1693 if (( $# != 3 )); then
1694 echo "$0: error, expected 3 arguments" >&2
1697 redir_path
="https://github.com/$github_path/releases/latest/download/"
1698 latest_prefix
=$
(curl
-s -I "$redir_path" |
awk 'tolower($1) == "location:" {print $2}')
1699 # it has a trailing /r at the end. just kill any whitespace.
1700 latest_prefix
="${latest_prefix//[$'\t\r\n ']}"
1701 if [[ ! $latest_prefix ]]; then
1702 echo "failed to find latest path. Tried to find case insensitive 'location:' in the curl output:"
1703 m curl
-s -I "$redir_path"
1706 version
="${latest_prefix##*/}"
1707 version
="${version#v}"
1708 m wget
-- "$latest_prefix/$file_prefix$version$file_suffix"
1712 # go-github-install restic/restic restic_ _linux_amd64.bz2
1713 # go-github-install restic/rest-server rest-server_ _linux_amd64.tar.gz
1715 # common pattern among go binaries on github
1716 go-github-install
() {
1717 local tmpd targetf tmp files src
1722 tmp
="${file_prefix##*[[:alnum:]]}"
1723 targetf
="${file_prefix%$tmp}"
1724 echo targetf
: $targetf
1725 github-release-dl
"$@"
1727 case $file_suffix in
1735 rm -f -- "${files[@]}"
1737 # Here we detect and handle 2 cases: either we extracted a single
1738 # binary which we have to rename or a folder with a binary named
1739 # $targetf in it which is all we care about.
1740 if (( ${#files[@]} == 1 )) && [[ -f ${files[0]} ]]; then
1742 mv -- .
/* /usr
/local
/bin
/$targetf
1744 files
=(.
/*/$targetf)
1745 if [[ -f $targetf ]]; then
1747 elif [[ -f ${files[0]} ]]; then
1751 mv -- "$src" /usr
/local
/bin
1757 ## 2024: I'm using gh instead of hub, but leaving this just in case.
1758 ## I tried the github cli tool (gh) and it seems easier than
1761 ## hub predated github's 2020 official cli tool gh.
1763 ## https://raw.githubusercontent.com/cli/cli/trunk/docs/gh-vs-hub.md
1764 # get latest hub and run it
1765 # main command to use:
1766 # hub pull-request --no-edit
1767 # --no-edit means to use the first commit\'s message as the pull request message.
1768 # If that fails, try doing
1769 # hub pull-request --no-edit -b UPSTREAM_OWNER:branch
1770 # where branch is usually master. it does the pr against your current branch.
1772 # On first use, you input username/pass and it gets an oath token so you dont have to repeat
1773 # it\'s at ~/.config/hub
1775 local up uptar updir p re
1776 # example https://github.com/github/hub/releases/download/v2.14.2/hub-linux-amd64-2.14.2.tgz
1777 up
=$
(wget
-q -O- https
://api.github.com
/repos
/github
/hub
/releases
/latest | jq
-r .assets
[].browser_download_url |
grep linux-amd64
)
1779 if [[ ! $up ||
$up =~
$re ]]; then
1780 echo "failed to get good update url. got: $up"
1784 if [[ ! -e /a
/opt
/$updir ]]; then
1785 rm -rf /a
/opt
/hub-linux-amd64
*
1787 tar -C /a
/opt
-zxf /a
/opt
/$uptar
1790 if ! which hub
&>/dev
/null
; then
1791 sudo
/a
/opt
/$updir/install
1794 # save token across computers
1795 if [[ ! -L ~
/.config
/hub
]]; then
1796 if [[ -e ~
/.config
/hub
]]; then
1797 mv ~
/.config
/hub
/p
/c
/subdir_files
/.config
/
1799 if [[ -e /p
/c
/subdir_files
/.config
/hub
]]; then
1813 # cvs update -C FILE
1818 # potentially useful command translation
1819 # https://fling.seas.upenn.edu/~giesen/dynamic/wordpress/equivalent-commands-for-git-svn-and-cvs/
1821 # importing cvs repo into git using git-cvs package:
1822 # /f/www $ /usr/lib/git-core/git-cvsimport -C /f/www-git
1838 find -L "$@" -not \
( -name .svn
-prune -o -name .git
-prune \
1839 -o -name .hg
-prune -o -name .editor-backups
-prune \
1840 -o -name .undo-tree-history
-prune \
) -iname "*$glob*" 2>/dev
/null
1844 # insensitive find here. args are combined into the search string.
1845 # -L = follow symlinks
1846 find -L .
-not \
( -name .svn
-prune -o -name .git
-prune \
1847 -o -name .hg
-prune -o -name .editor-backups
-prune \
1848 -o -name .undo-tree-history
-prune \
) -iname "*$**" 2>/dev
/null
1852 # insensitive find directory
1853 find -L .
-type d
-not \
( -name .svn
-prune -o -name .git
-prune \
1854 -o -name .hg
-prune -o -name .editor-backups
-prune \
1855 -o -name .undo-tree-history
-prune \
) -iname "*$**" 2>/dev
/null
1860 sudo iptables
-A INPUT
-s $1 -j DROP
1865 grep -Il "" "$@" &>/dev
/null
1872 # journalctl with times in the format the --since= and --until= options accept
1873 jrt
() { journalctl
-e -n100000 -o short-full
"$@"; }
1874 jr
() { journalctl
-e -n100000 "$@" ; }
1875 jrf
() { journalctl
-n1000 -f "$@" ; }
1877 # the invocation id is "assigned each time the unit changes from an inactive
1878 # state into an activating or active state" man systemd.exec
1879 journalctl
-e --no-tail -u exim4 _SYSTEMD_INVOCATION_ID
="$(systemctl show -p InvocationID --value $1)"
1881 ccomp journalctl jr jrf jru
1886 if [[ $PWD == /[iap
] ]]; then
1887 command ls -A --color=auto
-I lost
+found
"$@"
1889 command ls -A --color=auto
"$@"
1893 lcn
() { locate -i "*$**"; }
1895 lg
() { LC_COLLATE
=C.UTF-8 ll
--group-directories-first "$@"; }
1897 lt
() { ll
-tr "$@"; }
1899 lld
() { ll
-d "$@"; }
1901 ccomp
ls l lg lt lld ll
1907 for dirs in false true
; do
1909 if [[ -d $f ]]; then
1911 # reverse the order to rename the nested dirs first.
1912 # note: 0 element is the dir itself
1913 for ((i
=${#all[@]}-1; i
>=1; i--
)); do
1915 if $dirs && [[ -d $a ]]; then
1916 # e dirs low "$a" # debug
1918 elif ! $dirs && [[ ! -d $a && -e $a ]]; then
1920 # e not dirs low "$a" # debug
1925 # just rename all the top level args on the second pass
1927 # e final dirs low "$f" # debug
1934 low
() { # make filenames lowercase, remove bad chars
1937 arg
="${arg%%+(/)}" # remove trailing slashes. assumes we have extglob on.
1939 if (( ${#dir} == ${#arg} )); then
1943 new
="${f,,}" # downcase
1944 # shellcheck disable=SC2031 # seems like a shellcheck bug
1945 new
="${new//[^a-zA-Z0-9._-]/_}" # sub bad chars
1946 new
="${new#"${new%%[[:alnum:]]*}"}" # remove leading/trailing non-alnum
1947 new
="${new%"${new##*[[:alnum:]]}"}"
1948 # remove bad underscores, like __ and _._
1949 new
=$
(echo $new |
sed -r 's/__+/_/g;s/_+([.-])|([.-])_+/\1/g')
1950 safe_rename
"$dir/$f" "$dir/$new" ||
return 1
1955 lower
() { # make first letter of filenames lowercase.
1958 if [[ ${x::1} == [A-Z
] ]]; then
1959 y
=$
(tr '[:upper:]' '[:lower:]' <<<"${x::1}")"${x:1}"
1960 safe_rename
"$x" "$y" ||
return 1
1966 k
() { # history search
1967 grep -iP --binary-files=text
"$@" ${HISTFILE:-~/.bash_history} |
tail -n 80 ||
[[ $?
== 1 ]];
1969 ks
() { # history search with context
1970 # args are an extended regex used by sed
1971 history |
sed -nr "h;s/^\s*(\S+\s+){4}//;/$*/{g;p}" |
tail -n 80 ||
[[ $?
== 1 ]];
1973 ksu
() { # history search unique
1974 grep -P --binary-files=text
"$@" ${HISTFILE:-~/.bash_history} |
uniq ||
[[ $?
== 1 ]];
1977 # todo: id like to do maybe a daily or hourly cronjob to
1978 # check that my history file size is increasing. Ive had it
1979 # inexplicably truncated in the past.
1982 HISTTIMEFORMAT
='' history |
awk -v IGNORECASE
=1 '{ a=$1; sub(/^ *[^ ]+ */, "") }; /'"$*"'/'
1983 read -r -p "press anything but contrl-c to delete"
1984 for entry
in $
(HISTTIMEFORMAT
='' history |
awk -v IGNORECASE
=1 '{ a=$1; sub(/^ *[^ ]+ */, "") }; /'"$*"'/ { print a }' |
tac); do
1990 # history without the date
1992 history "$@" | cut
-d' ' -f 7-
1995 ccomp
grep k ks ksu histrm
1999 # show make targets, via http://stackoverflow.com/questions/3063507/list-goals-targets-in-gnu-make
2000 make -qp |
awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}'
2012 # mkdir the last arg, cp the rest into it
2015 cp "${@:1:$#-1}" "${@: -1}"
2019 mv "${@:1:$#-1}" "${@: -1}"
2022 mkt
() { # mkdir and touch file
2024 mkdir
-p "$(dirname "$path")"
2028 # shellcheck disable=SC2032
2029 mkdir
() { command mkdir
-p "$@"; }
2032 # https://github.com/HenriWahl/Nagstamon/issues/357
2033 if ! pgrep
-f /usr
/bin
/dunst
>/dev
/null
; then
2036 /usr
/bin
/nagstamon
&
2041 screen
-RD -S profanity
2044 # i dont want to wait for konsole to exit...
2046 command prof
&>/dev
/null
&
2051 printf '\033[1A\033[K'; printf "%s\n" "$l"| ts
"%F %T" |
tee -a /p
/self-chat.log
2056 # cant use s because sudo -i doesnt work for passwordless sudo command
2059 sudo nmtui-connect
"$@"
2069 if shopt nullglob
>/dev
/null
; then
2083 # shellcheck disable=SC2024
2085 for f
in /var
/log
/exim
4/paniclog
/var
/log
/exim
4/*panic
; do
2087 if [[ -s $f ]]; then
2088 echo ================== $f =============
2089 s
tee -a /var
/log
/exim
4/$base-archive <$f
2097 ping() { command ping -O "$@"; }
2098 p8
() { ping "$@" 8.8.8.8; }
2099 p6
() { ping6
"$@" 2001:4860:4860::8888; }
2101 pkx
() { # package extract
2102 local pkg cached tmp f
2105 # shellcheck disable=SC2012
2106 cached
=$
(ls -t /var
/cache
/apt
/archives
/${pkg}_
* |
tail -n1 2>/dev
/null
) ||
:
2107 if [[ $cached ]]; then
2110 m aptitude download
$pkg ||
return 1
2112 tmp
=(*); f
=${tmp[0]} # only 1 expected
2121 tmpf
=$
(pgrep
-f "$*")
2122 mapfile
-t pids
<<<"$tmpf"
2125 # shellcheck disable=SC2128
2131 0) echo "no pid found" ;;
2140 help="Usage: psg [--help] GREP_ARGS
2141 grep ps and output in a nice format"
2142 if [[ $1 == --help ]]; then
2147 # final grep is because some commands tend to have a lot of trailing spaces
2148 y
=$
(echo "$x" |
grep -iP "$@" |
grep -o '.*[^ ]') ||
:
2150 echo "$x" |
head -n 1 ||
[[ $?
== 141 ]]
2155 pubip
() { curl
-4s https
://icanhazip.com
; }
2156 pubip6
() { curl
-6s https
://icanhazip.com
; }
2157 whatismyip
() { pubip
; }
2160 q
() { # start / launch a program in the backround and redir output to null
2164 # shellcheck disable=SC2120
2166 if [[ $HISTFILE ]]; then
2167 history -a # save history
2169 trap ERR
# this avoids a segfault
2171 # i had this redir, not sure why
2172 # exit "$@" 2>/dev/null
2175 # scp is insecure and deprecated.
2177 rsync
-Pt --inplace "$@"
2182 # available high ports are 1024-65535,
2183 # but lets skip things that are more likely to be in use
2186 print(secrets.SystemRandom().randrange(10002,65500))
2192 # shellcheck disable=SC1090 # expected to not follow
2202 # rsync, root is required to keep permissions right.
2203 # rsync --archive --human-readable --verbose --itemize-changes --checksum \(-ahvic\) \
2204 # --no-times --delete
2205 # basically, make an exact copy, use checksums instead of file times to be more accurate
2206 rsync
-ahvic --delete "$@"
2209 # like rlu, but dont delete files on the target end which
2210 # do not exist on the original end.
2214 # rl without preserving modification time.
2215 rsync
-ahvic --delete --no-t "$@"
2217 # [RSYNC_OPTS] HOST PATH
2219 # eg. rsu -opts frodo /testpath
2220 # relative paths will expanded with readlink -f.
2221 opts
=("${@:1:$#-2}") # 1 to last -2
2222 path
="${*:$#}" # last
2223 host="${*:$#-1:1}" # last -1
2224 if [[ $path == .
* ]]; then
2225 path
=$
(readlink
-f $path)
2227 m rsync
-ahvi --relative --no-implied-dirs "${opts[@]}" "$path" "root@$host:/";
2229 ccomp rsync rsd rsa rst rsu
2231 # find programs listening on a port
2234 # to figure out these args, i had to look at the man page from git version, as of 2022-04.
2235 s ss
-lpn state listening sport
= $port
2240 if [[ $
(systemctl is-active nscd ||
:) != inactive
]]; then
2245 hr
; s ss
-lpn sport
= 53
2246 if systemctl is-enabled dnsmasq
&>/dev
/null ||
[[ $
(systemctl is-active dnsmasq ||
:) != inactive
]]; then
2247 # this will fail is dnsmasq is failed
2248 hr
; m ser status dnsmasq |
cat ||
:
2250 hr
; echo $f:; ccat
$f
2251 hr
; m grr
'^ *(servers-file|server) *=|^ *no-resolv *$' /etc
/dnsmasq.conf
/etc
/dnsmasq.d
2252 f
=/etc
/dnsmasq-servers.conf
2253 hr
; echo $f:; ccat
$f
2256 echo /etc
/nsswitch.conf
:
2257 grep '^ *hosts:' /etc
/nsswitch.conf
2258 if systemctl is-enabled systemd-resolved
&>/dev
/null ||
[[ $
(systemctl is-active systemd-resolved ||
:) != inactive
]]; then
2259 hr
; m ser status systemd-resolved |
cat ||
:
2260 hr
; m resolvectl status |
cat
2268 if [[ $
(systemctl is-active nscd ||
:) != inactive
]]; then
2272 m sudo nscd
-i hosts
2274 if [[ $
(systemctl is-active dnsmasq ||
:) != inactive
]]; then
2275 m sudo systemctl restart dnsmasq
2277 if [[ $
(systemctl is-active systemd-resolved ||
:) != inactive
]]; then
2278 m sudo systemctl restart systemd-resolved
2280 if type -P resolvectl
&>/dev
/null
; then
2281 resolvectl flush-caches
2285 # add annoyingly long argument which should be the default
2287 sed -i --follow-symlinks "$@"
2292 # todo: test variable assignment with newlines here.
2293 # https://stackoverflow.com/questions/15783701/which-characters-need-to-be-escaped-when-using-bash
2295 # beware that it only works on the assumption that any special
2296 # characters in the input string are intended to be escaped, not to work
2297 # as special chacters.
2299 LC_ALL
=C
sed -e 's/[^a-zA-Z0-9,._+@%/-]/\\&/g; 1{$s/^$/""/}; 1!s/^/"/; $!s/$/"/'
2303 ssh fencepost
head -n 300 /gd
/gnuorg
/EventAndTravelInfo
/rms-current-trips.txt |
less
2312 command sudo
"$@" ||
return $?
2317 # I use a function because otherwise we cant use in a script,
2318 # cant assign to variable.
2320 # note: gksudo is recommended for X apps because it does not set the
2321 # home directory to the same, and thus apps writing to ~ fuck things up
2322 # with root owned files.
2324 if [[ $EUID != 0 ||
$1 == -* ]]; then
2325 # shellcheck disable=SC2034
2326 SUDOD
="$PWD" command sudo
-i "$@"
2332 sb
() { # sudo bash -c
2333 # use sb instead of s is for sudo redirections,
2334 # eg. sb 'echo "ok fine" > /etc/file'
2335 # shellcheck disable=SC2034
2337 sudo
-i bash
-c "$@"
2340 se
() { s urun
0077 "$@"; }
2343 safe_rename
() { # warn and dont rename if file exists.
2344 # mv -n exists, but it\'s silent
2345 if [[ $# != 2 ]]; then
2346 echo safe_rename error
: $# args
, need
2 >&2
2349 if [[ $1 != "$2" ]]; then # yes, we want to silently ignore this
2350 if [[ -e $2 ||
-L $2 ]]; then
2351 echo "Cannot rename $1 to $2 as it already exists."
2360 sudo
dd status
=none of
="$1"
2364 if type -p systemctl
&>/dev
/null
; then
2367 if (( $# >= 3 )); then
2368 echo iank
: ser expected
2 or
less arguments
2375 systemctl
-n 40 status
"$@"
2378 seru
() { systemctl
--user "$@"; }
2379 # like restart, but do nothing if its not already started
2382 if [[ $
(s systemctl
--no-pager show
-p ActiveState
$service ) == ActiveState
=active
]]; then
2383 systemctl restart
$service
2387 setini
() { # set a value in a .ini style file
2388 key
="$1" value
="$2" section
="$3" file="$4"
2389 if [[ -s $file ]]; then
2390 sed -ri -f - "$file" <<EOF
2391 # remove existing keys
2392 / *\[$section\]/,/^ *\[[^]]+\]/{/^\s*${key}[[:space:]=]/d}
2394 /^\s*\[$section\]/a $key=$value
2395 # from section to eof, do nothing
2396 /^\s*\[$section\]/,\$b
2397 # on the last line, if we haven't found section yet, add section and key
2409 sgo
() { # service go
2411 ser restart
$service ||
return 1
2412 if type -p systemctl
&>/dev
/null
; then
2418 # ignore services that dont exist
2419 if systemctl
cat $service &>/dev
/null
; then
2421 ser disable
$service
2427 systemctl list-unit-files | rg
"$@"
2432 # disable a warning with:
2433 # shellcheck disable=SC2206 # reasoning
2435 # see bash-template/style-guide.md for justifications
2438 quotes
=2048,2068,2086,2206,2254
2439 others
=2029,2032,2033,2054,2164,
2440 shellcheck
-W 999 -x -e $quotes,$others "$@" ||
return $?
2442 # sk with quotes. For checking scripts that we expect to take untrusted
2443 # input in order to verify we quoted vars.
2446 others
=2029,2033,2054,2164
2447 shellcheck
-W 999 -x -e $others "$@" ||
return $?
2452 for f
in $
(i s |
awk '$1 == "modified:" {print $2}'); do
2453 if istext
"$f" && [[ $
(head -n1 "$f" 2>/dev
/null
) == '#!/bin/bash'* ]]; then
2459 # sl: ssh, but firsh rsync our bashrc and related files to a special
2460 # directory on the remote host if needed.
2462 # Some environment variables and files need to be setup for this to work
2463 # (mine are set at the beginning of this file)
2465 # SL_FILES_DIR: Environment variable. Path to folder which should at
2466 # least have a .bashrc file or symlink. This dir will be rsynced to ~ on
2467 # remote hosts (top level symlinks are resolved) unless the host already
2468 # has a $SL_FILES_DIR/.bashrc. In that case, we assume it is a host you
2469 # control and sync files to separately and already has the ~/.bashrc you
2470 # want. The remote bash will also take its .inputrc config from this
2471 # folder (default of not existing is fine). Mine looks like this:
2472 # https://iankelling.org/git/?p=distro-setup;a=tree;f=sl/.iank
2474 # SL_INFO_DIR: Environment variable. This folder stores info about what
2475 # we detected on the remote system and when we last synced. It will be created
2476 # if it does not exist. Sometimes you may want to forget about a
2477 # remote system, you can use sl --rsync, or the function for that slr
2480 # SL_TEST_CMD: Env var. Meant to be used to vary the files synced
2481 # depending on the remote host. Run this string on the remote host the
2482 # first time sl is run (or if we run slr). The result is passed to
2483 # SL_TEST_HOOK. For example,
2484 # export SL_TEST_CMD=". /etc/os-release ; echo \${VERSION//[^a-zA-Z0-9]/}"
2486 # SL_TEST_HOOK: Env var. It is run as $SL_TEST_HOOK. This can set
2487 # $SL_FILES_DIR to vary the files synced.
2489 # SL_RSYNC_ARGS: Env var. String of arguments passed to rsync. For
2490 # example to exclude files within a directory. Note, excluded
2491 # files wont be deleted on rsync, you can add --delete-excluded
2492 # to the rsync command if that is desired.
2494 # SL_SSH_ARGS: Env var. Default arguments passed to ssh.
2496 # For when ~/.bashrc is already customized on the remote server, you
2497 # might find it problematic that ~/.bashrc is sourced for ALL ssh
2498 # commands, even in scripts. This paragraph is all about that. bash
2499 # scripts dont source ~/.bashrc, but call ssh in scripts and you get
2500 # ~/.bashrc. You dont want this. .bashrc is meant for interactive shells
2501 # and if you customize it, probably has bugs from time to time. This is
2502 # bad. Here's how I fix it. I have a special condition to "return" in my
2503 # .bashrc for noninteractive ssh shells (copy that code). Then use this
2504 # function or similar that passes LC_USEBASHRC=t when sshing and I want
2505 # my bashrc. Also, I don't keep most of my bashrc in .bashrc, i source a
2506 # separate file because even if I return early on, the whole file gets
2507 # parsed which can fail if there is a syntax error.
2509 # Background on LC_USEBASHRC var (no need to read if you just want to
2510 # use this function): env variables sent across ssh are strictly
2511 # limited, but we get LC_* at least in debian based machines, so we
2512 # just make that * be something no normal program would use. Note, on
2513 # hosts that dont allow LC_* I start an inner shell with LC_USEBASHRC
2514 # set, and the inner shell also allows running a nondefault
2515 # .bashrc. This means the outer shell still ran the default .bashrc,
2516 # but that is the best we can do.
2518 local now args remote dorsync haveinfo tmpa sshinfo tmp tmp2
type info_sec force_rsync \
2519 sync_dirname testcmd extra_info testbool files_sec sl_test_cmd sl_test_hook
2520 declare -a args tmpa
2524 # ssh [-1246Antivivisectionist] [-b bind_address] [-c cipher_spec] [-D [bind_address:]port]
2525 # [-E log_file] [-e escape_char] [-F configfile] [-I pkcs11] [-i identity_file] [-L address]
2526 # [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port] [-Q query_option]
2527 # [-R address] [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]] [user@]hostname
2530 # ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]
2531 # [-D [bind_address:]port] [-E log_file] [-e escape_char]
2532 # [-F configfile] [-I pkcs11] [-i identity_file]
2533 # [-J [user@]host[:port]] [-L address] [-l login_name] [-m mac_spec]
2534 # [-O ctl_cmd] [-o option] [-p port] [-Q query_option] [-R address]
2535 # [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]]
2538 if [[ $1 == --rsync ]]; then
2542 # shellcheck disable=SC2153 # intentional
2543 sl_test_cmd
=$SL_TEST_CMD
2544 # shellcheck disable=SC2153 # intentional
2545 sl_test_hook
=$SL_TEST_HOOK
2546 # shellcheck disable=SC2153 # intentional
2547 sl_rsync_args
=$SL_RSYNC_ARGS
2574 # note we dont support things like -4oOption
2575 -[46AaCfGgKkMNnqsTtVvXxYy
]*)
2578 -[bcDEeFIiJLlmOopQRSWw
]*)
2579 # -oOption etc is valid
2580 if (( ${#1} >= 3 )); then
2583 args
+=("$1" "$2"); shift 2
2592 if [[ ! $remote ]]; then
2593 echo $0: error hostname required
>&2
2598 if [[ ! $SL_INFO_DIR ]]; then
2599 echo 'error: missing SL_INFO_DIR env var' >&2
2605 tmpa
=($SL_INFO_DIR/???????????
"$remote")
2607 if [[ -e $sshinfo ]]; then
2608 if $force_rsync; then
2615 tmp
=${sshinfo[0]##*/}
2618 extra_info
=$
(cat $sshinfo)
2620 # we test for string to know ssh succeeded
2621 testbool
="test -e $SL_FILES_DIR/.bashrc -a -L .bashrc -a -v LC_USEBASHRC"
2622 testcmd
="if $testbool; then printf y; else printf n; fi"
2623 if ! tmp
=$
(LC_USEBASHRC
=y
command ssh "${args[@]}" "$remote" "$testcmd; $sl_test_cmd"); then
2624 echo failed sl
test. doing plain
ssh -v
2625 command ssh -v "${args[@]}" "$remote"
2627 if [[ $tmp == y
* ]]; then
2633 extra_info
="${tmp:1}"
2635 if [[ $sl_test_hook ]]; then
2636 RSYNC_RSH
="ssh ${args[*]}" $sl_test_hook "$extra_info" "$remote"
2639 if $haveinfo && [[ $type == b
]]; then
2641 read -r files_sec _
< <(find -L $SL_FILES_DIR -printf "%T@ %p\n" |
sort -nr ||
[[ $?
== 141 ||
${PIPESTATUS[0]} == 32 ]] )
2642 files_sec
=${files_sec%%.*}
2643 if (( files_sec
> info_sec
)); then
2649 sync_dirname
=${SL_FILES_DIR##*/}
2651 if [[ ! $SL_FILES_DIR ]]; then
2652 echo 'error: missing SL_FILES_DIR env var' >&2
2657 RSYNC_RSH
="ssh ${args[*]}" m rsync
-rptL --delete $sl_rsync_args $SL_FILES_DIR "$remote":
2659 if $dorsync ||
! $haveinfo; then
2660 sshinfo
=$SL_INFO_DIR/$EPOCHSECONDS$type"$remote"
2661 [[ -e $SL_INFO_DIR ]] || mkdir
-p $SL_INFO_DIR
2662 printf "%s\n" "$extra_info" >$sshinfo
2665 if [[ $type == b
]]; then
2666 if (( ${#@} )); then
2667 # Theres a couple ways to pass arguments, im not sure whats best,
2668 # but relying on bash 4.4+ escape quoting seems most reliable.
2669 command ssh "${args[@]}" "$remote" \
2670 LC_USEBASHRC
=t bash
-c '.\ '$sync_dirname'/.bashrc\;"\"\$@\""' bash
${@@Q}
2671 elif [[ ! -t 0 ]]; then
2672 # This case is when commands are being piped to ssh.
2673 # Normally, no bashrc gets sourced.
2674 # But, since we are doing all this, lets source it because we can.
2675 cat <(echo .
$sync_dirname/.bashrc
) - |
command ssh "${args[@]}" "$remote" LC_USEBASHRC
=t bash
2677 command ssh -t "${args[@]}" "$remote" LC_USEBASHRC
=t INPUTRC
=$sync_dirname/.inputrc bash
--rcfile $sync_dirname/.bashrc
2681 LC_USEBASHRC
=t
command ssh "${args[@]}" "$remote" ${@@Q}
2683 command ssh "${args[@]}" "$remote" LC_USEBASHRC
=t bash
2686 # this function inspired from https://github.com/Russell91/sshrc
2693 sl
-oControlMaster=no
-oControlPath=/ "$@"
2695 # kill off old shared socket then ssh
2697 m
ssh -O exit "$@" ||
[[ $?
== 255 ]]
2700 ccomp
ssh sl slr sss ssk
2703 if [[ $TERM == alacritty ||
$TERM == xterm-kitty
]]; then
2704 TERM
=xterm-256color LC_USEBASHRC
=t
command ssh "$@"
2706 LC_USEBASHRC
=t
command ssh "$@"
2712 # log with script. timing is $1.t and script is $1.s
2713 # -l to save to ~/typescripts/
2714 # -t to add a timestamp to the filenames
2715 local logdir do_stamp arg_base
2716 (( $# >= 1 )) ||
{ echo "arguments wrong"; return 1; }
2719 while getopts "lt" option
2722 l
) arg_base
=$logdir ;;
2725 echo error
: bad option
2730 shift $
((OPTIND
- 1))
2732 [[ -e $logdir ]] || mkdir
-p $logdir
2733 $do_stamp && arg_base
+=$
(date +%F.
%T
%z
)
2734 script -t $arg_base.s
2> $arg_base.t
2736 splay
() { # script replay
2737 #logRoot="$HOME/typescripts/"
2738 #scriptreplay "$logRoot$1.t" "$logRoot$1.s"
2739 scriptreplay
"$1.t" "$1.s"
2743 # sudo redo. be aware, this command may not work right on strange distros or earlier software
2744 if [[ $# == 0 ]]; then
2745 sudo
-E bash
-c -l "$(history -p '!!')"
2747 echo this
command redos last
history item. no argument is accepted
2752 # with -ll, less secure but faster.
2753 command srm
-ll "$@"
2758 ssh $1 "/tmp/${2##*/}" "$(printf "%q
\n" "${@:2}")"
2770 tclock
() { # terminal clock
2775 # this goes to full width
2776 #len=${1:-$((COLUMNS -7))}
2779 if (( x
== len
)); then
2781 d
="$(date +%l:%_M) "
2784 d
=$
(date +%l
:%M
:%_S
)
2788 for ((i
=0; i
<x
; i
++)); do
2789 if (( i
% 6 )); then
2807 # test existence / exists
2810 [[ -e "$x" ||
-L "$x" ]] || ret
=1
2816 # normally, i would just execute these commands in the function.
2817 # however, DEBUG is not inherited, so we need to run it outside a function.
2818 # And we want to run set -x afterwards to avoid spam, so we cram everything
2819 # in here, and then it will run after this function is done.
2820 # # set as array to satisfy shellcheck, but it is equivalent to setting it as non-array
2821 PROMPT_COMMAND
=('trap DEBUG; unset PROMPT_COMMAND; PS1="\w \$ "')
2824 PROMPT_COMMAND
=(prompt-command
)
2825 if [[ $TERM == *(screen
*|xterm
*|rxvt
*) ]]; then
2826 trap 'settitle "$BASH_COMMAND"' DEBUG
2830 # prometheus node curl
2833 host=${1:-127.0.0.1}
2834 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
2837 tx
() { # toggle set -x, and the prompt so it doesnt spam
2838 if [[ $
- == *x
* ]]; then
2847 # show all processes in the network namespace $1.
2848 # blank entries appear to be subprocesses/threads
2852 sudo
find -L /proc
/[1-9]*/task
/*/ns
/net
-samefile /run
/netns
/$netns | cut
-d/ -f5 | \
2854 x
=$
(ps
-w --no-headers -p $l);
2855 if [[ $x ]]; then echo "$x"; else echo $l; fi;
2859 if ! s ip netns list |
grep -Fx nonet
&>/dev
/null
; then
2860 s ip netns add nonet
2862 sudo
-E env
/sbin
/ip netns
exec nonet sudo
-E -u iank
/bin
/bash
2865 m
() { printf "%s\n" "$*"; "$@"; }
2867 # update file. note: duplicated in mail-setup.
2868 # updates $ur u result to true or false
2869 # updates $reload to true if file updated is in /etc/systemd/system
2871 local tmp tmpdir dest
="$1"
2872 local base
="${dest##*/}"
2873 local dir
="${dest%/*}"
2874 if [[ $dir != "$base" ]]; then
2875 # dest has a directory component
2878 # shellcheck disable=SC2034 # see comment at top of function
2880 tmpdir
="$(mktemp -d)"
2881 cat >$tmpdir/"$base"
2882 tmp
=$
(rsync
-ic $tmpdir/"$base" "$dest")
2884 printf "%s\n" "$tmp"
2885 # shellcheck disable=SC2034 # see comment at top of function
2887 if [[ $dest == /etc
/systemd
/system
/* ]]; then
2888 # shellcheck disable=SC2034 # see comment at top of function
2897 if type -p uprecords
&>/dev
/null
; then
2905 for x
in "$@"; do virsh destroy
"$x"; virsh undefine
"$x"; done
2913 sudo virsh dumpxml
$vm |
sed -r "s/(<listen.*address=')([^']+)/\1$ip/" | \
2914 sed -r "s/listen='[^']+/listen='$ip/"> $t
2915 sudo virsh undefine
$vm
2916 sudo virsh define
$t
2921 vm-set-listen
$1 0.0.0.0
2926 vm-set-listen
$1 127.0.0.1
2931 interfaces
=$
(iw dev |
awk '$1 == "Interface" {print $2}')
2932 for i
in $interfaces; do
2933 echo "myiwscan: considering $i"
2934 # find input, copy to pattern space, when we find the first field, print the copy in different order without newlines.
2935 # instead of using labels, we could just match a line and group, eg: /signal:/,{s/signal:(.*)/\1/h}
2936 sudo iw dev
$i scan |
sed -rn "
2937 s/^\Wcapability: (.*)/\1/;Ta;h;b
2938 :a;s/^\Wsignal: -([^.]+).*/\1/;Tb;H;b
2939 # padded to min width of 20
2940 :b;s/\WSSID: (.*)/\1 /;T;s/^(.{20}(.*[^ ])?) */\1/;H;g;s/(.*)\n(.*)\n(.*)/\2 \3 \1/gp;b
2945 # Run script by copying it to a temporary location first,
2946 # and changing directory, so we don't have any open
2947 # directories or files that could cause problems when
2964 # spark 1 5 22 13 53
2968 # Copyright (c) Zach Holman, https://zachholman.com
2969 # https://github.com/holman/spark
2971 # As of 2022-10-28, I reviewed github forks that had several newer
2972 # commits, none had anything interesting. I did a little refactoring
2973 # mostly to fix emacs indent bug.
2975 # Generates sparklines.
2978 if [ "X$1" = "X-n" ]; then
2992 # find min/max values
2993 local min
=0xffffffff max
=0
2997 # on Linux (or with bash4) we could use `printf %.0f $n` here to
2998 # round the number but that doesn't work on OS X (bash3) nor does
2999 # `awk '{printf "%.0f",$1}' <<< $n` work, so just cut it off
3001 (( n
< min
)) && min
=$n
3002 (( n
> max
)) && max
=$n
3003 numbers
=$numbers${numbers:+ }$n
3007 local ticks
=(▁ ▂ ▃ ▄ ▅ ▆ ▇ █
)
3009 # use a high tick if data is constant
3010 (( min
== max
)) && ticks
=(▅ ▆
)
3013 f
=$
(( ( (max-min
) <<8)/( tc - 1) ))
3018 _spark_echo -n ${ticks[$(( (((n-min)<<8)/f) ))]}
3023 pdfwc() { local f; for f; do echo "$f" "$(pdfinfo "$f" | awk '/^Pages:/ {print $2}')"; done }
3026 # nvm install script appended this to my .bashrc. I dont want to run it all the time,
3027 # so put it in a function.
3029 export NVM_DIR="$HOME/.nvm"
3030 # shellcheck disable=SC1091 # may not exist, & third party
3031 [ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh" # This loads nvm
3032 # shellcheck disable=SC1091 # may not exist, & third party
3033 [ -s "$NVM_DIR/bash_completion" ] && source "$NVM_DIR/bash_completion" # This loads nvm bash_completion
3038 if date -d 'february 29' &>/dev/null; then
3048 if [[ -e /sys/class/power_supply/AC/online && $(</sys/class/power_supply/AC/online) == 0 ]]; then
3055 # make vim work with my light colortheme terminal.
3057 if [[ -e ~/.vimrc ]]; then
3060 command vim -c ':colorscheme peachpuff' "$@"
3064 # ls count. usage: pass a directory, get the number of files.
3065 # https://unix.stackexchange.com/questions/90106/whats-the-most-resource-efficient-way-to-count-how-many-files-are-in-a-director
3067 # shellcheck disable=SC2790 disable=SC2012 # intentional
3071 # run then notify. close notification after the next prompt.
3074 dunstify -u critical -h string:x-dunst-stack-tag:profanity "$*"
3075 _psrun=(dunstctl close-all)
3078 dunstify -u critical -h string:x-dunst-stack-tag:profanity n
3079 _psrun=(dunstctl close-all)
3085 inotifywait -m "$dir" -e create -e moved_to | while read -r _ _ file; do
3099 if ! type -p sponge &>/dev/null; then
3100 echo "$0: error: missing dependency: sudo apt install moreutils" >&2
3105 echo "adding header to $f"
3106 if [[ -s $f ]]; then
3111 cat - "${f_maybe[@]}" <<EOF | sponge "$f"
3112 The following is the GNU All-permissive License as recommended in
3113 <https://www.gnu.org/licenses/license-recommendations.en.html>
3115 Copyright (C) $(date +%Y) Free Software Foundation <sysadmin@fsf.org>
3117 Copying and distribution of this file, with or without modification,
3118 are permitted in any medium without royalty provided the copyright
3119 notice and this notice are preserved. This file is offered as-is,
3120 without any warranty.
3122 Contributions are welcome. See <https://savannah.gnu.org/maintenance/fsf/>.
3130 "$@" |& ts || return $?
3137 if $use_color && type -p tput &>/dev/null; then
3138 # this is nice for a dark background terminal:
3139 # https://github.com/trapd00r/LS_COLORS
3140 # I would like if there was something similar for light.
3142 # the default bold green is too light.
3143 # this explains the codes: https://gist.github.com/thomd/7667642
3144 export LS_COLORS=ex=1
3146 term_bold="$(tput bold)"
3147 term_red="$(tput setaf 1)"
3148 term_green="$(tput setaf 2)"
3149 # shellcheck disable=SC2034 # expected
3150 term_yellow="$(tput setaf 3)"
3151 term_purple="$(tput setaf 5)"
3152 term_nocolor="$(tput sgr0)" # no font attributes
3154 # unused so far. commented for shellcheck
3155 # term_underl="$(tput smul)"
3156 # term_blue="$(tput setaf 4)"
3157 # term_cyan="$(tput setaf 6)"
3159 # Try to keep environment pollution down, EPA loves us.
3160 unset safe_term match_lhs use_color
3165 if [[ $- == *i* ]]; then
3170 if [[ $EUID == 1000 ]]; then
3177 # this needs to come before next ps1 stuff
3178 # this stuff needs bash 4, feb 2009,
3179 # old enough to no longer condition on $BASH_VERSION anymore
3183 if [[ $- == *i* ]] && [[ ! $LC_INSIDE_EMACS ]]; then
3185 bind -m vi-command B:shell-backward-word
3186 bind -m vi-command W:shell-forward-word
3189 if [[ $SSH_CLIENT || $SUDO_USER ]]; then
3190 unset PROMPT_DIRTRIM
3194 # emacs terminal has problems if this runs slowly,
3195 # so I've thrown a bunch of things at the wall to speed it up.
3197 local return=$? # this MUST COME FIRST
3198 local ps_char ps_color
3201 if [[ $HISTFILE ]]; then
3202 history -a # save history
3206 0) ps_color="$term_purple"
3209 *) ps_color="$term_green"
3210 ps_char="$return \\$"
3213 if [[ ! -O . ]]; then # not owner
3214 if [[ -w . ]]; then # writable
3215 ps_color="$term_bold$term_red"
3217 ps_color="$term_bold$term_green"
3221 # faster than sourceing the file im guessing
3222 if [[ -e /dev/shm/iank-status && ! -e /tmp/quiet-status ]]; then
3223 eval "$(< /dev/shm/iank-status)"
3225 if [[ $MAIL_HOST && $MAIL_HOST != "$HOSTNAME" ]]; then
3226 ps_char="@ $ps_char"
3229 if [[ $(jobs -p) ]]; then
3234 # allow a function to specify a command to run after we run the next
3235 # command. Use case: a function makes a persistent notification. If
3236 # we happen to be using that terminal, we can just keep working by
3237 # entering our next command, even a noop in order to dismiss the
3238 # notification, instead of having to explicitly dismiss it.
3239 if [[ ${_psrun[*]} ]]; then
3240 if (( _psrun_count >= 1 )); then
3246 _psrun_count=$(( _psrun_count + 1 ))
3252 # We could test if sudo is active with sudo -nv
3253 # but then we get an email and log of lots of failed sudo commands.
3254 # We could turn those off, but seems better not to.
3255 if [[ $EUID != 0 ]] && [[ $DID_SUDO ]]; then
3256 psudo="\[$term_bold$term_red\]s\[$term_nocolor\] "
3258 if [[ ! $HISTFILE ]]; then
3259 ps_char="NOHIST $ps_char"
3261 PS1="${PS1%"${PS1#*[wW]}"} $jobs_char$psudo\[$ps_color\]$ps_char\[$term_nocolor\] "
3263 # copy of what is automatically added by guix.
3264 # adds [env] to PS1 if GUIX_ENVIRONMENT is set and PS1 contains '$';
3265 if [ -n "$GUIX_ENVIRONMENT" ]; then
3266 if [[ $PS1 =~ (.*)"\\$" ]]; then
3267 PS1="${BASH_REMATCH[1]} [env]\\\$ "
3272 # set titlebar. instead, using more advanced
3274 #echo -ne "$_title_escape $HOSTNAME ${PWD/#$HOME/~} \007"
3276 PROMPT_COMMAND=(prompt-command)
3278 if [[ $TERM == screen* ]]; then
3279 _title_escape="\033]..2;"
3281 # somme sites recommend this, i dunno what the diff is.
3282 #_title_escape="\033]30;"
3283 _title_escape="\033]0;"
3286 # make the titlebar be the last command and the current directory.
3290 # These are some checks to help ensure we dont set the title at
3291 # times that the debug trap is running other than the case we
3292 # want. Some of them might not be needed.
3293 if (( ${#FUNCNAME[@]} != 1 || ${#BASH_ARGC[@]} != 2 || BASH_SUBSHELL != 0 )); then
3296 if [[ $1 == prompt-command ]]; then
3299 echo -ne "$_title_escape ${PWD/#$HOME/~} "
3304 # note, this wont work:
3305 # x=$(mktemp); cp a $x
3306 # I havnt figured out why, bigger fish to fry.
3309 # condition from the screen man page i think.
3310 # note: duplicated in tx()
3311 if [[ $TERM == *(screen*|xterm*|rxvt*) ]]; then
3312 trap 'settitle "$BASH_COMMAND"' DEBUG
3319 # * stuff that makes sense to be at the end
3325 if [[ -s "$HOME/.rvm/scripts/rvm" ]]; then
3326 # shellcheck disable=SC1091
3327 source "$HOME/.rvm/scripts/rvm"
3330 # I had this idea to start a bash shell which would run an initial
3331 # command passed through this env variable, then continue on
3332 # interactively. But the use case I had in mind went away.
3334 # if [[ $MY_INIT_CMD ]]; then
3335 # "${MY_INIT_CMD[@]}"
3339 # ensure no bad programs appending to this file will have an affect