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
351 path-add
--ifexists /usr
/local
/go
/bin
359 if [[ -s $path ]]; then
360 # shellcheck disable=SC1090 # this is dynamic, shellcheck can't follow it.
362 elif [[ -s $bashrc_dir/$file ]]; then
363 # shellcheck disable=SC1090 # this is dynamic, shellcheck can't follow it.
364 source $bashrc_dir/$file
369 mysrc
/a
/bin
/small-misc-bash
/ll-function
370 mysrc
/a
/bin
/distro-functions
/src
/package-manager-abstractions
372 # things to remember:
373 # ALT-C - cd into the selected directory
374 # CTRL-T - Paste the selected file path into the command line
376 # good guide to some of its basic features is the readme file
377 # https://github.com/junegunn/fzf
379 # if [[ -s /usr/share/doc/fzf/examples/key-bindings.bash ]]; then
380 # source /usr/share/doc/fzf/examples/key-bindings.bash
386 # temporary functions
388 m
"${@//spring/fall}"
391 e
"${@//spring/fall}"
395 ### begin FSF section ###
397 # Comments before functions are meant to be good useful
398 # documentation. If they fail at that, please improve them or send Ian a
401 ## copy bash completion
403 # It copies how the bash completion works from one command to other
404 # commands. Generally just use within a .bashrc.
406 # Usage: ORIGINAL_COMMAND TARGET_COMMAND...
412 if ! c
=$
(complete
-p $src 2>/dev
/null
); then
413 _completion_loader
$src &>/dev
/null ||
:
414 c
=$
(complete
-p $src 2>/dev
/null
) ||
return 0
422 ## BEGIN functions to change directory better than cd ##
426 # c: acts like cd, but stores directory history: you could alias to cd if you wanted.
429 # cl: list recent directories and optionally choose one.
431 # Finer details you may want to skip:
433 # bl: print the list of back and forward directories.
435 # We keep 2 stacks of directories, forward and back. Unlike with a web
436 # browser, the forward stack is not erased when going somewhere new.
438 # Recent directories are stored in ~/.cdirs.
440 declare -a _dir_forward _dir_back
442 # normally, the top of _dir_back is our current dir. if it isn't,
443 # put it on there, except we don't want to do that when we
444 # just launched a shell
445 if [[ $OLDPWD ]]; then
446 if (( ${#_dir_back[@]} == 0 )) ||
[[ ${_dir_back[-1]} != "$PWD" ]]; then
451 if (( ${#_dir_back[@]} == 0 )) ||
[[ ${_dir_back[-1]} != "$PWD" ]]; then
454 echo "$PWD" >> ~
/.cdirs
461 if (( ${#_dir_back[@]} == 0 )); then
462 echo "nothing left to go back to" >&2
465 top_back
="${_dir_back[-1]}"
467 if [[ $top_back == "$PWD" ]] && (( ${#_dir_back[@]} == 1 )); then
468 echo "already on last back entry" >&2
473 if [[ $top_back == "$PWD" ]]; then
474 # add to dirf if not already there
475 if (( ${#_dir_forward[@]} == 0 )) ||
[[ ${_dir_forward[-1]} != "$top_back" ]]; then
476 _dir_forward
+=("$top_back")
478 unset "_dir_back[-1]"
479 command cd "${_dir_back[-1]}"
481 if (( ${#_dir_forward[@]} == 0 )) ||
[[ ${_dir_forward[-1]} != "$PWD" ]]; then
482 _dir_forward
+=("$PWD")
484 command cd "$top_back"
487 # Interesting feature, not sure I want it.
488 # give us a peek at what is next in the list
489 # if (( ${#_dir_back[@]} >= 2 )); then
490 # printf "%s\n" "${_dir_back[-2]}"
494 # c/b/f Implementation notes:
496 # The top of the back is $PWD
497 # as long as the last directory change was due to c,b,or cl.
499 # Example of stack changes:
525 if (( ${#_dir_forward[@]} == 0 )); then
526 echo "no forward dir left" >&2
529 top_forward
="${_dir_forward[-1]}"
530 unset "_dir_forward[-1]"
533 # give us a peek at what is next in the list
534 # if (( ${#_dir_forward[@]} )); then
535 # printf "%s\n" "${_dir_forward[-1]}"
540 local i line input start
541 local -A buttondirs alines
542 local -a buttons
dirs lines
543 buttons
=( {a..z
} {2.
.9} )
544 if [[ ! -s ~
/.cdirs
]]; then
545 echo nothing
in ~
/.cdirs
551 mapfile
-t lines
<~
/.cdirs
552 start
=$
(( ${#lines[@]} - 1 ))
554 # we have ~33 buttons as of this writing, so lets
555 # prune down the history every once in a while.
556 if (( start
> 500 )); then
557 tac ~
/.cdirs |
awk '!seen[$0]++' |
head -n 200 |
tac | sponge ~
/.cdirs ||
[[ $?
== 141 ]]
560 for (( j
=start
; j
>= 0; j--
)); do
562 if [[ ! $line ||
${alines[$line]} ||
! -d "$line" ||
$line == "$PWD" || line
== "$HOME" ]]; then
566 buttondirs
[${buttons[i]}]="$line"
567 printf "%s %s\n" ${buttons[i]} "$line"
568 # the LINES bit is for when we have a short terminal, just dont print all
569 # the directories. alternative would be to do something like less the list.
570 if (( i
== ${#buttons[@]} - 1 )) ||
{ [[ $LINES ]] && (( i
== LINES
- 3 )); }; then
576 if (( i
== 0 )); then
577 echo "no dirs in ~/.cdirs"
581 if [[ $input != $
'\n' ]]; then
582 c
"${buttondirs[$input]}"
585 # bl = back list. lists the back and forward directories. i tend to
586 # forget this exists and use cl instead.
590 start
=$
(( ${#_dir_back[@]} - 1 ))
592 # cleanup possible repeating of pwd
593 if (( start
>= 0 )) && [[ ${_dir_back[$start]} == "$PWD" ]]; then
594 start
=$
(( start
- 1 ))
597 if (( start
>= 0 )); then
598 for (( i
=start
; i
>= 0 ; i--
)); do
599 printf "%s %s\n" $j ${_dir_back[i]}
601 if (( j
>= max
)); then
608 start
=$
(( ${#_dir_forward[@]} - 1 ))
610 # cleanup possible repeating of pwd
611 if (( start
>= 0 )) && [[ ${_dir_forward[$start]} == "$PWD" ]]; then
612 start
=$
(( start
- 1 ))
614 if (( start
< 0 )); then
619 for (( i
=start
; i
>= 0 ; i--
)); do
620 printf "%s %s\n" $j ${_dir_forward[i]}
622 if (( j
>= max
)); then
627 # like running cl <enter> a <enter>
630 mapfile
-t lines
<~
/.cdirs
631 start
=$
(( ${#lines[@]} - 1 ))
632 for (( j
=start
; j
>= 0; j--
)); do
634 if [[ ! $line ||
! -d "$line" ||
$line == "$PWD" || line
== "$HOME" ]]; then
642 ## END functions to change directory better than cd ##
644 # pee do. run args as a command with output copied to syslog.
646 # Usage: pd [-t TAG] COMMAND...
648 # -t TAG Override the tag in the syslog. The default is COMMAND with
649 # any path part is removed, eg. for /bin/cat the tag is cat.
651 # You can view the log via "journalctl -t TAG"
657 -t) tag
="$2"; shift 2 ;;
659 echo "PWD=$PWD command: $*" | logger
-t $tag
660 "$@" |
& pee
cat "logger -t $tag" || ret
=$?
661 echo "exited with status=$ret" | pee
cat "logger -t $tag"
662 # this avoids any err-catch
663 (( ret
== 0 )) ||
return $ret
667 # jdo = journal do. Run command as transient systemd service, tailing
668 # its output in the journal until it completes.
670 # Usage: jdo COMMAND...
672 # Compared to pd: commands recognize this is a non-interactive shell.
673 # The service is unaffected if our ssh connection dies, no need to run
676 # Note: The last few lines of any existing entries for a unit by that
677 # name will be output first, and there will be a few second delay at the
678 # start of the command, and a second or so at the end.
680 # Note: Functions and aliases obviously won't work, we resolve the
683 # Note: requires running as root.
685 local cmd cmd_name jr_pid ret
689 if [[ $EUID != 0 ]]; then
690 echo "jdo: error: rerun as root"
694 if [[ $cmd != /* ]]; then
695 cmd
=$
(type -P "$cmd")
698 journalctl
-qn2 -f -u "$cmd_name" &
699 # Trial and error of time needed to avoid missing initial lines.
700 # .5 was not reliable. 1 was not reliable. 2 was not reliable
703 systemd-run
--unit "$cmd_name" --wait --collect "$cmd" "$@" || ret
=$?
704 # The sleep lets the journal output its last line
705 # before the prompt comes up.
707 kill $jr_pid &>/dev
/null ||
:
710 # this avoids any err-catch
711 (( ret
== 0 )) ||
return $ret
715 # standard date as used in logs
720 # date in log appropriate format
727 command ts
"%F %T" "$@"
730 # ts log. log command to log file.
731 # usage: tsl LOG_PATH_PREFIX COMMAND...
732 # example: tsl /root/command
733 # log file will be like /root/command-2024-02-10.log
735 local log_prefix log_path appending ret
736 if (( $# < 2 )); then
737 echo "tsl: error: expected >= 2 arguments, got $#" >&2
741 if [[ $log_prefix == */* && ! -d ${log_prefix%*/} ]]; then
742 echo "tsl: error: expected directory at ${log_prefix%*/}" >&2
745 log_path
=$log_prefix-$
(date +%Y-
%m-
%d
).log
747 if [[ -s $log_path ]]; then
751 printf "%s\n" "CWD: $PWD, log: $log_path, running $*" | ts
"%F %T" |
tee -a "$log_path"
753 "$@" |
& ts
"%F %T" |
tee -a "$log_path" || ret
=$?
754 printf "%s\n" "exit code $ret from command: $*" | ts
"%F %T" |
tee -a "$log_path"
756 printf "%s\n" "note: this log file contains logs before those of previous command" | ts
"%F %T" |
tee -a "$log_path"
762 mapfile
-t cmds
<<'EOF'
763 tail -n +1 /proc/mdstat /etc/mdadm/mdadm.conf /etc/fstab /etc/crypttab
766 ls -la /dev/disk/by-id
769 for cmd
in "${cmds[@]}"; do
789 ....
() { c ..
/..
/..
; }
790 .....
() { c ..
/..
/..
/..
; }
791 ......
() { c ..
/..
/..
/..
/..
; }
796 path
=$
(readlink
-e "$f")
797 echo "cat >$path <<'EOF'"
804 # file cut copy and paste, like the text buffers :)
805 # I havnt tested these.
806 _fbufferinit
() { # internal use
807 ! [[ $my_f_tempdir ]] && my_f_tempdir
="$(mktemp -d)"
808 rm -rf "${my_f_tempdir:?}"/*
812 cp "$@" "$my_f_tempdir"/
816 mv "$@" "$my_f_tempdir"/
818 fpst
() { # file paste
819 [[ $2 ]] && { echo too many arguments
; return 1; }
821 cp "$my_f_tempdir"/* "$target"
825 local host ip port
file key tmp
826 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" ||
: )
827 file=$
(readlink
-f ~
/.ssh
/known_hosts
)
829 echo "khfix: ssh failed"
832 if [[ $port != 22 ]]; then
833 ip_entry
="[$ip]:$port"
834 host_entry
="[$host]:$port"
839 if [[ $host != "$ip" ]]; then
841 ssh-keygen
-F "$host_entry" -f $file >$tmp ||
[[ $?
== 1 ]] # 1 when it doesnt exist in the file
842 if [[ -s $tmp ]]; then
843 key
=$
(sed -r 's/^.*([^ ]+ +[^ ]+) *$/\1/' $tmp)
847 grep -Fv "$key" "$file" | sponge
"$file"
852 ssh-keygen
-F "$ip_entry" -f $file >$tmp ||
[[ $?
== 1 ]]
853 if [[ -s $tmp ]]; then
854 key
=$
(sed -r 's/^.*([^ ]+ +[^ ]+) *$/\1/' $tmp)
858 grep -Fv "$key" "$file" | sponge
"$file"
860 ll ~
/.ssh
/known_hosts
862 khfix-r
() { # known hosts fix + root
863 _khfix-common
"$@" ||
return 1
868 _khfix-common
"$@" ||
return 1
872 # copy path into clipboard
875 x
=$
(readlink
-nf "${1:-$PWD}")
876 # yes, its kinda dumb that xclip/xsel cant do this in one invocation.
877 # And, summarizing this:
878 # https://askubuntu.com/questions/705620/xclip-vs-xsel
879 # xclip has a few more options. xclip has a bug in tmux / forwarded x sessions.
883 # clipboard a string (into selection & clipboard buffer)
885 # yes, its kinda dumb that xclip/xsel cant do this in one invocation.
886 # And, summarizing this:
887 # https://askubuntu.com/questions/705620/xclip-vs-xsel
888 # xclip has a few more options. xclip has a bug in tmux / forwarded x sessions.
889 printf "%s" "$*" | xclip
-selection clipboard
890 printf "%s" "$*" | xclip
893 # a1 = awk {print $1}
894 for field
in {1.
.20}; do
895 eval a
$field"() { awk '{print \$$field}'; }"
898 for num
in {1.
.9}; do
899 eval h
$num"() { head -n$num || [[ \$? == 141 ]]; }"
904 # shellcheck disable=SC2046 disable=SC2001 disable=SC2183 # hacks, expected
905 printf '%d.%d.%d.%d\n' $
(echo $1 |
sed 's/../0x& /g')
909 local f out outdir
in fname origdir skip1
913 while [[ $1 == -* ]]; do
915 # if we got interrupted after 1st phase
927 # first pass only uses about 1 cpu, so run in parallel
931 if [[ $f == /* ]]; then
936 out
="$origdir/$outdir/$fname"
937 mkdir
-p /tmp
/vp
9/$fname
939 if ! $skip1 && [[ ! -s ffmpeg2pass-0.log
]]; then
940 # -nostdin or else wait causes ffmpeg to go into stopped state. dunno why, random stackoverflow answer.
941 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
943 if [[ -e $out ]]; then rm -f $out; fi
944 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
951 utcl
() { # utc 24 hour time to local hour 24 hour time
952 echo "print( ($1 $(date +%z | sed -r 's/..$//;s/^(-?)0*/\1/')) % 24)"|python3
960 # for running in a fai rescue. iank specific.
962 d
=vgata-Samsung_SSD_850_EVO_2TB_S2RLNX0J502123D
963 for f
in $d vgata-Samsung_SSD_870_QVO_8TB_S5VUNG0N900656V
; do
964 cryptsetup luksOpen
--key-file /p
/dev
/$f/root crypt-
$f-root
965 cryptsetup luksOpen
--key-file /p
/dev
/$f/o crypt-
$f-o
967 mount
-o subvol
=root_trisquelaramo
/dev
/mapper
/crypt-
$d-root /mnt
968 mount
-o subvol
=a
/dev
/mapper
/crypt-
$d-root /mnt
/a
969 mount
-o subvol
=o
/dev
/mapper
/crypt-
$d-o /mnt
/o
970 mount
-o subvol
=boot_trisquelaramo
/dev
/sda2
/mnt
/boot
978 c4
() { c
/var
/log
/exim4
; }
980 caa
() { git commit
--amend --no-edit -a; }
993 find -L "$@" -type f
-not \
( -name .svn
-prune -o -name .git
-prune \
994 -o -name .hg
-prune -o -name .editor-backups
-prune \
995 -o -name .undo-tree-history
-prune \
) -printf '%h\0%d\0%p\n' |
sort -t '\0' -n \
996 |
awk -F '\0' '{print $3}' 2>/dev
/null |
while read -r file; do
998 printf "%s\n" "$file"
1005 calc
() { echo "scale=3; $*" |
bc -l; }
1006 # no having to type quotes, but also no command history:
1010 echo "scale=3; $x" |
bc -l
1021 ccat
() { # config cat. see a config without extra lines.
1022 sed -r '/^[[:space:]]*([;#]|--|\/\/|$)/d' "$@"
1028 # dev/pts needed for pacman signature check
1029 for d
in dev proc sys dev
/pts
; do
1031 if ! mountpoint
$d &>/dev
/null
; then
1032 m s mount
-o bind /$d $d
1038 # dev/pts needed for pacman signature check
1039 for d
in dev
/pts dev proc sys
; do
1041 if mountpoint
$d &>/dev
/null
; then
1049 # join options which are continued to multiples lines onto one line
1051 while IFS
= read -r line
; do
1052 # remove leading spaces/tabs. assumes extglob
1053 if [[ $line == "[ ]*" ]]; then
1054 line
="${line##+( )}"
1059 elif [[ $line == *=* ]]; then
1060 echo "$pastline" >> "$2"
1063 pastline
="$pastline $line"
1065 done < <(grep -vE '^([ \t]*#|^[ \t]*$)' "$1")
1066 echo "$pastline" >> "$2"
1070 # diff config files,
1071 # setup for format of postfix, eg:
1074 local pastline unified f1 f2
1078 _cdiff-prep
"$1" "$f1"
1079 _cdiff-prep
"$2" "$f2"
1080 cat "$f1" "$f2" |
grep -Po '^[^=]+=' |
sort |
uniq > "$unified"
1081 while IFS
= read -r line
; do
1082 # the default bright red / blue doesnt work in emacs shell
1083 dwdiff
-cblue,red
-A best
-d " ," <(grep "^$line" "$f1" ||
echo ) <(grep "^$line" "$f2" ||
echo ) | colordiff
1089 local start
=$SECONDS
1091 # shellcheck disable=SC2030
1092 inotifywait
-m "$dir" -e create
-e moved_to | \
1093 while read -r filedir _
file; do
1096 calc $
((SECONDS
- start
)) / 60
1103 s chown
-R $USER:$USER "$@"
1106 # shellcheck disable=SC2032
1108 # makes it so chown -R symlink affects the symlink and its target.
1109 if [[ $1 == -R ]]; then
1111 command chown
-h "$@"
1112 command chown
-R "$@"
1123 d
() { builtin bg "$@"; }
1126 # f would be more natural, but i already am using it for something
1127 z
() { builtin fg "$@"; }
1130 x
() { builtin kill %%; }
1133 diff --strip-trailing-cr -w "$@" # diff content
1141 safe_rename
"$x" "$y"
1146 # usage: dfp MOUNTPOINT [SECOND_INTERVAL]
1147 # SECOND_INTERVAL defaults to 90
1150 local a b mp interval
1153 if [[ ! $mp ]]; then
1154 echo "dfp: error, missing 1st arg" >&2
1158 a
=$
(df
--output=used
$mp |
tail -n1)
1160 b
=$
(df
--output=used
$mp |
tail -n1)
1161 printf "used mib: %'d mib/min: %s\n" $
(( b
/1000 )) $
(( (b-a
) / (interval
* 1000 / 60 ) ))
1165 # get ipv4 ip from HOST. or if it is already a number, return that
1173 getent ahostsv4
"$host" |
awk '{ print $1 }' |
head -n1
1179 command dig +nostats
+nocmd
"$@"
1181 # Output with sections sorted, and removal of query id, so 2 dig outputs can be diffed.
1185 dig +nordflag
"$@" |
sed -r 's/^(;; ->>HEADER<<-.*), id: .*/\1/' |
while read -r l
; do
1186 if [[ $l == [^\
;]* ]]; then
1190 printf "%s" "$sec" |
sort
1198 # compare digs to the 2 servers
1199 # usage: digdiff @server1 @server2 DIG_ARGS
1200 # note: only the soa master nameserver will respond with
1201 # ra "recursive answer" flag. That difference is meaningless afaik.
1208 digsort
$s1 "$@" |
tee /tmp
/digdiff
1209 diff -u /tmp
/digdiff
<(digsort
$s2 "$@")
1212 # date in a format i like reading
1214 date "+%A, %B %d, %r" "$@"
1219 # date with all digits in a format i like
1223 ccomp
date dt dtr dtd
1225 dus
() { # du, sorted, default arg of
1226 du
-sh ${@:-*} |
sort -h
1231 e
() { printf "%s\n" "$*"; }
1239 printf "%qEOL\n" "${arg}"
1240 printf "%s" "${arg}" |
& hexdump -C
1244 # echo variables. print var including escapes, etc, like xxd for variable
1250 if [[ -v $arg ]]; then
1251 printf "%qEOL\n" "${!arg}"
1252 printf "%s" "${!arg}" |
& hexdump -C
1254 echo arg
$arg is
unset
1260 [[ ${#@} == 2 ]] ||
{ echo "error: ediff requires 2 arguments"; return 1; }
1261 emacs
--eval "(ediff-files \"$1\" \"$2\")"
1265 # shellcheck disable=SC2120 # we expect to pass arguments in use outside this file
1268 tail -F /var
/log
/exim
4/mainlog
/var
/log
/exim
4/*main
/var
/log
/exim
4/paniclog
/var
/log
/exim
4/*panic
-n 200 "$@"
1272 tail -F /var
/log
/exim
4/mainlog
-n 200 "$@"
1275 tail -F /var
/log
/exim
4/mymain
-n 200 "$@"
1277 ccomp
tail etail etail2
1279 # ran into this online, trying it out
1281 ( "$@" &>/dev
/null
& disown )
1285 ssh "$@" cat .ssh
/authorized_keys
{,2}
1289 # print exim old pids
1291 local configtime pid piduptime now daemonpid
1292 printf -v now
'%(%s)T' -1
1293 configtime
=$
(stat
-c%Y
/var
/lib
/exim
4/config.autogenerated
)
1294 if [[ -s /run
/exim
4/exim.pid
]]; then
1295 daemonpid
=$
(cat /run
/exim
4/exim.pid
)
1297 for pid
in $
(pgrep
-f '^/usr/sbin/exim4( |$)'); do
1298 # the daemonpid gets reexeced on HUP (service reloads), keeping its same old timestamp
1299 if [[ $pid == "$daemonpid" ]]; then
1302 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
1303 if (( configtime
> now
- piduptime
)); then
1309 # exim tail but only watch lines from new pids
1312 for pid
in $
(eoldpids
); do
1315 if [[ $oldpids ]]; then
1316 etail |
awk '$3 !~ /^\[('"${oldpids%|}"')\]$/'
1321 # exim watch as old pids go away
1323 local configtime pid piduptime now tmpstr
1329 mapfile
-t oldpids
<<<"$tmpstr"
1330 if (( ! ${#oldpids[@]} )); then
1333 # print the date every 20 iterations
1334 if (( ! count
% 20 )); then
1338 ps
-f -p "${oldpids[*]}"
1344 less /var
/log
/exim
4/mainlog
1348 exiqgrep
-ir.\
* -o 60 |
while read -r i
; do
1351 hlm exigrep
$i /var
/log
/exim
4/mainlog |
cat ||
:
1355 # other ways to get the list of message ids:
1356 # exim -bp | awk 'NF == 4 {print $3}'
1357 # # this is slower 160ms, vs 60.
1359 exiqgrep
-ir.\
* |
xargs exim
-Mrm
1364 mkdir
-p /tmp
/edev
/etc
1365 cp -ra /etc
/exim4
/tmp
/edev
/etc
1366 cp -ra /etc
/alias* /tmp
/edev
/etc
1367 find /tmp
/edev
/etc
/exim4
-type f
-execdir sed -i "s,/etc/,/tmp/edev/etc/,g" '{}' +
1371 update-exim4.conf
-d /tmp
/edev
/etc
/exim4
-o /tmp
/edev
/e.conf
1375 # show important information about incoming mail in the exim log
1377 sed -rn '/testignore|jtuttle|eximbackup/!s/^[^ ]+ ([^ ]+) [^ ]+ [^ ]+ <= ([^ ]+).*T="(.*)" from (<[^ ]+> .*$)/\1 \4\n \3/p' <${1:-/var/log/exim4/mainlog}
1380 # 2nd line is message-id:
1382 sed -rn '/testignore|jtuttle|eximbackup/!s/^[^ ]+ ([^ ]+) [^ ]+ [^ ]+ <= ([^ ]+).* id=([^ ]+) T="(.*)" from (<[^ ]+> .*$)/\1 \5\n \3\n \4/p' <${1:-/var/log/exim4/mainlog}
1385 tail -F /var
/log
/exim
4/mainlog |
sed -rn '/testignore|jtuttle|eximbackup/!s/^[^ ]+ ([^ ]+) [^ ]+ [^ ]+ <= ([^ ]+).*T="(.*)" from (<[^ ]+> .*$)/\1 \4\n \3/p'
1392 # find array. make an array of file names found by find into $x
1393 # argument: find arguments
1394 # return: find results in an array $x
1395 while read -rd ''; do
1397 done < <(find "$@" -print0);
1400 faf
() { # find all files. use -L to follow symlinks
1401 find "$@" -not \
( -name .svn
-prune -o -name .git
-prune \
1402 -o -name .hg
-prune -o -name .editor-backups
-prune \
1403 -o -name .undo-tree-history
-prune \
) -type f
2>/dev
/null
1406 # usage ffconcat FILES_TO_CONCAT OUTPUT_FILE
1410 printf "file '%s'\n" "$1" >$tmpf
1411 while (( $# > 1 )); do
1413 printf "file '%s'\n" "$1" >>$tmpf
1415 # https://trac.ffmpeg.org/wiki/Concatenate
1416 ffmpeg
-f concat
-safe 0 -i $tmpf -c copy
"$1"
1421 if (( $# == 0 )); then
1422 echo ffremux error expected args
>&2
1427 tmpf
=$tmpd/"${f##*/}"
1428 ffmpeg
-i "$f" -c:v copy
-c:a copy
$tmpf
1436 # absolute path of file/dir without resolving symlinks.
1438 # Most of the time, I want this where I would normally use readlink.
1439 # This is what realpath -s does in most cases, but sometimes it
1440 # actually resolves symlinks, at least when they are in /.
1442 # Note, if run on a dir, if the final component is relative, it won't
1443 # resolve that. Use the below fpd for that.
1445 # note: we could make a variation of this which
1446 # assigns to a variable name using eval, so that we don't have to do
1447 # x=$(fp somepath), which might save subshell overhead and look nice,
1448 # but I'm not going to bother.
1450 local initial_oldpwd initial_pwd dir base
1451 initial_oldpwd
="$OLDPWD"
1453 if [[ $1 == */* ]]; then
1456 # CDPATH because having it set will cause cd to possibly print output
1458 printf "%s%s\n" "$PWD" "$base"
1459 CDPATH
='' cd "$initial_pwd"
1460 OLDPWD
="$initial_oldpwd"
1462 printf "%s/%s\n" "$PWD" "$1"
1465 # full path of directory without resolving symlinks
1467 local initial_oldpwd initial_pwd dir
1468 initial_oldpwd
="$OLDPWD"
1472 printf "%s%s\n" "$PWD" "$base"
1474 OLDPWD
="$initial_oldpwd"
1481 sudo mailq |gr frozen|
awk '{print $3}' |
while read -r id
; do
1487 echo -e '\n\n##############################\n'
1488 done |
tee -a /tmp
/frozen
1492 while read -r line
; do
1493 printf '%s\n' "$line"
1494 ids
+=("$(printf '%s\n' "$line" |gr frozen|awk '{print $3}')")
1496 echo "sleeping for 2 in case you change your mind"
1498 sudo exim
-Mrm "${ids[@]}"
1502 # like -e for functions. returns on error.
1503 # at the end of the function, disable with:
1505 trap 'echo "${BASH_COMMAND:+BASH_COMMAND=\"$BASH_COMMAND\" }
1506 ${FUNCNAME:+FUNCNAME=\"$FUNCNAME\" }${LINENO:+LINENO=\"$LINENO\" }\$?=$?"
1512 local help="Usage: getdir [--help] PATH
1513 Output the directory of PATH, or just PATH if it is a directory."
1514 if [[ $1 == --help ]]; then
1518 if [[ $# -ne 1 ]]; then
1519 echo "getdir error: expected 1 argument, got $#"
1522 if [[ -d $1 ]]; then
1526 dir
="$(dirname "$1")"
1527 if [[ -d $dir ]]; then
1530 echo "getdir error: directory does not exist"
1536 git_empty_branch
() { # start an empty git branch. carefull, it deletes untracked files.
1537 [[ $# == 1 ]] ||
{ echo 'need a branch name!'; return 1;}
1539 root
=$
(gitroot
) ||
return 1 # function to set gitroot
1541 git symbolic-ref HEAD refs
/heads
/$1
1546 # shellcheck disable=SC2120
1548 local help="Usage: gitroot [--help]
1549 Print the full path to the root of the current git repo
1551 Handles being within a .git directory, unlike git rev-parse --show-toplevel,
1552 and works in older versions of git which did not have that."
1553 if [[ $1 == --help ]]; then
1558 p
=$
(git rev-parse
--git-dir) ||
{ echo "error: not in a git repo" ; return 1; }
1559 [[ $p != /* ]] && p
=$PWD
1565 local args gdb
=false
1567 if [[ $EMACSDIR ]]; then
1568 path-add
"$EMACSDIR/lib-src" "$EMACSDIR/src"
1571 if [[ $DISPLAY ]]; then
1575 if (( $# == 0 )); then
1578 # duplicate -c, but oh well
1579 if ! pgrep
-u $EUID emacsclient
; then
1580 if (( $# == 0 )) && type -p gdb
&>/dev
/null
; then
1586 if [[ $EMACSDIR ]]; then
1588 # todo: we don't have to alter HOME since emacs 29+, we can set
1589 # user-emacs-directory with the flag --init-directory
1591 # Alter the path here, otherwise the nfs mount gets triggered on the
1592 # first path lookup when emacs is not being used.
1593 # shellcheck disable=SC2098 disable=SC2097 # false positive
1594 PATH
="$EMACSDIR/lib-src:$EMACSDIR/src:$PATH" EHOME
=$HOME HOME
=$EMACSDIR m emacsclient
-a "" $args "$@"
1597 # due to a bug, we cant debug from the start unless we get a new gdb
1598 # https://sourceware.org/bugzilla/show_bug.cgi?id=24454
1599 # m gdb -ex="set follow-fork-mode child" -ex=r -ex=quit --args emacs --daemon
1600 m emacsclient
-a "" $args "$@"
1602 cd "/a/opt/emacs-$(distro-name)$(distro-num)"
1603 s gdb
-p "$(pgrep -f 'emacs --daemon')" -ex c
1606 m emacsclient
-a "" $args "$@"
1611 # g pipe. like: cmd | emacs. save cmd output to tmp file, then edit.
1617 #like cmd &> tempfile; emacs tempfile
1619 # note: a useful workflow for doing mass replace on my files:
1621 ## remove any false positives, or manually edit them. rename files if needed.
1622 # sedi 's/REGEX/REPLACEMENT/' $(gr '^/' /a/tmp/gtmp)
1627 # g command substitution.
1629 # shellcheck disable=SC2046 # i want word splitting for this hackery
1633 # force terminal version
1639 # quit will prompt if the program crashes.
1640 gdb
-ex=r
-ex=quit
--args emacs
"$@"; r
;
1644 # kill the emacs daemon
1649 grep -iIP --color=auto
"$@" ||
return $?
1651 grr
() { # grep recursive
1652 # Don't return 1 on nonmatch because this is meant to be
1653 # interactive, not in a conditional.
1654 if [[ ${#@} == 1 ]]; then
1655 grep --exclude-dir='*.emacs.d' --exclude-dir='*.git' -riIP --color=auto
"$@" . ||
[[ $?
== 1 ]]
1657 grep --exclude-dir='*.emacs.d' --exclude-dir='*.git' -riIP --color=auto
"$@" ||
[[ $?
== 1 ]]
1665 # recursive everything. search for files/dirs and lines. rs = easy chars to press
1669 find "$@" -not \
( -name .svn
-prune -o -name .git
-prune \
1670 -o -name .hg
-prune -o -name .editor-backups
-prune \
1671 -o -name .undo-tree-history
-prune \
) 2>/dev
/null |
grep -iP --color=auto
"$query"
1675 # horizontal row. used to break up output
1678 # 180 is long enough.
1679 blocks
=██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
1680 printf "%s\n" "$(tput setaf 5 2>/dev/null ||:)${blocks:0:${COLUMNS:-180}}$(tput sgr0 2>/dev/null||:)"
1684 local col input_len
=0
1686 input_len
=$
((input_len
+ 1 + ${#arg}))
1688 col=$
((60 - input_len
))
1689 printf "\e[1;97;41m%s" "$*"
1690 if (( col > 0 )); then
1691 # shellcheck disable=SC2046 # needed to work as intended. a better way would be like hr above.
1692 printf "\e[1;97;41m \e[0m%.0s" $
(eval echo "{1..${col}}")
1696 hlm
() { hl
"$*"; "$@"; }
1698 hrcat
() { local f
; for f
; do [[ -f $f ]] ||
continue; hr
; echo "$f"; cat "$f"; done }
1701 # github-release-dl restic/restic restic_ _linux_amd64.bz2
1703 # https://github.com/restic/restic/releases/download/v0.16.3/restic_0.16.3_linux_amd64.bz2
1704 github-release-dl
() {
1705 local github_path file_prefix file_suffix latest_prefix version redir_path
1709 if (( $# != 3 )); then
1710 echo "$0: error, expected 3 arguments" >&2
1713 redir_path
="https://github.com/$github_path/releases/latest/download/"
1714 latest_prefix
=$
(curl
-s -I "$redir_path" |
awk 'tolower($1) == "location:" {print $2}')
1715 # it has a trailing /r at the end. just kill any whitespace.
1716 latest_prefix
="${latest_prefix//[$'\t\r\n ']}"
1717 if [[ ! $latest_prefix ]]; then
1718 echo "failed to find latest path. Tried to find case insensitive 'location:' in the curl output:"
1719 m curl
-s -I "$redir_path"
1722 version
="${latest_prefix##*/}"
1723 version
="${version#v}"
1724 m wget
-- "$latest_prefix/$file_prefix$version$file_suffix"
1728 # go-github-install restic/restic restic_ _linux_amd64.bz2
1729 # go-github-install restic/rest-server rest-server_ _linux_amd64.tar.gz
1731 # common pattern among go binaries on github
1732 go-github-install
() {
1733 local tmpd targetf tmp files src
1738 tmp
="${file_prefix##*[[:alnum:]]}"
1739 targetf
="${file_prefix%"$tmp"}"
1740 echo targetf
: $targetf
1741 github-release-dl
"$@"
1743 case $file_suffix in
1751 rm -f -- "${files[@]}"
1753 # Here we detect and handle 2 cases: either we extracted a single
1754 # binary which we have to rename or a folder with a binary named
1755 # $targetf in it which is all we care about.
1756 if (( ${#files[@]} == 1 )) && [[ -f ${files[0]} ]]; then
1758 mv -- .
/* /usr
/local
/bin
/$targetf
1760 files
=(.
/*/$targetf)
1761 if [[ -f $targetf ]]; then
1763 elif [[ -f ${files[0]} ]]; then
1767 mv -- "$src" /usr
/local
/bin
1773 ## 2024: I'm using gh instead of hub, but leaving this just in case.
1774 ## I tried the github cli tool (gh) and it seems easier than
1777 ## hub predated github's 2020 official cli tool gh.
1779 ## https://raw.githubusercontent.com/cli/cli/trunk/docs/gh-vs-hub.md
1780 # get latest hub and run it
1781 # main command to use:
1782 # hub pull-request --no-edit
1783 # --no-edit means to use the first commit\'s message as the pull request message.
1784 # If that fails, try doing
1785 # hub pull-request --no-edit -b UPSTREAM_OWNER:branch
1786 # where branch is usually master. it does the pr against your current branch.
1788 # On first use, you input username/pass and it gets an oath token so you dont have to repeat
1789 # it\'s at ~/.config/hub
1791 local up uptar updir p re
1792 # example https://github.com/github/hub/releases/download/v2.14.2/hub-linux-amd64-2.14.2.tgz
1793 up
=$
(wget
-q -O- https
://api.github.com
/repos
/github
/hub
/releases
/latest | jq
-r .assets
[].browser_download_url |
grep linux-amd64
)
1795 if [[ ! $up ||
$up =~
$re ]]; then
1796 echo "failed to get good update url. got: $up"
1800 if [[ ! -e /a
/opt
/$updir ]]; then
1801 rm -rf /a
/opt
/hub-linux-amd64
*
1803 tar -C /a
/opt
-zxf /a
/opt
/$uptar
1806 if ! which hub
&>/dev
/null
; then
1807 sudo
/a
/opt
/$updir/install
1810 # save token across computers
1811 if [[ ! -L ~
/.config
/hub
]]; then
1812 if [[ -e ~
/.config
/hub
]]; then
1813 mv ~
/.config
/hub
/p
/c
/subdir_files
/.config
/
1815 if [[ -e /p
/c
/subdir_files
/.config
/hub
]]; then
1829 # cvs update -C FILE
1834 # potentially useful command translation
1835 # https://fling.seas.upenn.edu/~giesen/dynamic/wordpress/equivalent-commands-for-git-svn-and-cvs/
1837 # importing cvs repo into git using git-cvs package:
1838 # /f/www $ /usr/lib/git-core/git-cvsimport -C /f/www-git
1854 find -L "$@" -not \
( -name .svn
-prune -o -name .git
-prune \
1855 -o -name .hg
-prune -o -name .editor-backups
-prune \
1856 -o -name .undo-tree-history
-prune \
) -iname "*$glob*" 2>/dev
/null
1860 # insensitive find here. args are combined into the search string.
1861 # -L = follow symlinks
1862 find -L .
-not \
( -name .svn
-prune -o -name .git
-prune \
1863 -o -name .hg
-prune -o -name .editor-backups
-prune \
1864 -o -name .undo-tree-history
-prune \
) -iname "*$**" 2>/dev
/null
1868 # insensitive find directory
1869 find -L .
-type d
-not \
( -name .svn
-prune -o -name .git
-prune \
1870 -o -name .hg
-prune -o -name .editor-backups
-prune \
1871 -o -name .undo-tree-history
-prune \
) -iname "*$**" 2>/dev
/null
1876 sudo iptables
-A INPUT
-s $1 -j DROP
1881 grep -Il "" "$@" &>/dev
/null
1888 # journalctl with times in the format the --since= and --until= options accept
1889 jrt
() { journalctl
-e -n100000 -o short-full
"$@"; }
1890 jr
() { journalctl
-e -n100000 "$@" ; }
1891 jrf
() { journalctl
-n1000 -f "$@" ; }
1893 # the invocation id is "assigned each time the unit changes from an inactive
1894 # state into an activating or active state" man systemd.exec
1895 journalctl
-e --no-tail -u exim4 _SYSTEMD_INVOCATION_ID
="$(systemctl show -p InvocationID --value $1)"
1897 ccomp journalctl jr jrf jru
1902 if [[ $PWD == /[iap
] ]]; then
1903 command ls -A --color=auto
-I lost
+found
"$@"
1905 command ls -A --color=auto
"$@"
1909 lcn
() { locate -i "*$**"; }
1911 lg
() { LC_COLLATE
=C.UTF-8 ll
--group-directories-first "$@"; }
1913 lt
() { ll
-tr "$@"; }
1915 lld
() { ll
-d "$@"; }
1917 ccomp
ls l lg lt lld ll
1923 for dirs in false true
; do
1925 if [[ -d $f ]]; then
1927 # reverse the order to rename the nested dirs first.
1928 # note: 0 element is the dir itself
1929 for ((i
=${#all[@]}-1; i
>=1; i--
)); do
1931 if $dirs && [[ -d $a ]]; then
1932 # e dirs low "$a" # debug
1934 elif ! $dirs && [[ ! -d $a && -e $a ]]; then
1936 # e not dirs low "$a" # debug
1941 # just rename all the top level args on the second pass
1943 # e final dirs low "$f" # debug
1950 low
() { # make filenames lowercase, remove bad chars
1953 arg
="${arg%%+(/)}" # remove trailing slashes. assumes we have extglob on.
1955 if (( ${#dir} == ${#arg} )); then
1959 new
="${f,,}" # downcase
1960 # shellcheck disable=SC2031 # seems like a shellcheck bug
1961 new
="${new//[^a-zA-Z0-9._-]/_}" # sub bad chars
1962 new
="${new#"${new%%[[:alnum:]]*}"}" # remove leading/trailing non-alnum
1963 new
="${new%"${new##*[[:alnum:]]}"}"
1964 # remove bad underscores, like __ and _._
1965 new
=$
(echo $new |
sed -r 's/__+/_/g;s/_+([.-])|([.-])_+/\1/g')
1966 safe_rename
"$dir/$f" "$dir/$new" ||
return 1
1971 lower
() { # make first letter of filenames lowercase.
1974 if [[ ${x::1} == [A-Z
] ]]; then
1975 y
=$
(tr '[:upper:]' '[:lower:]' <<<"${x::1}")"${x:1}"
1976 safe_rename
"$x" "$y" ||
return 1
1982 k
() { # history search
1983 grep -iP --binary-files=text
"$@" ${HISTFILE:-~/.bash_history} |
tail -n 80 ||
[[ $?
== 1 ]];
1985 ks
() { # history search with context
1986 # args are an extended regex used by sed
1987 history |
sed -nr "h;s/^\s*(\S+\s+){4}//;/$*/{g;p}" |
tail -n 80 ||
[[ $?
== 1 ]];
1989 ksu
() { # history search unique
1990 grep -P --binary-files=text
"$@" ${HISTFILE:-~/.bash_history} |
uniq ||
[[ $?
== 1 ]];
1993 # todo: id like to do maybe a daily or hourly cronjob to
1994 # check that my history file size is increasing. Ive had it
1995 # inexplicably truncated in the past.
1998 HISTTIMEFORMAT
='' history |
awk -v IGNORECASE
=1 '{ a=$1; sub(/^ *[^ ]+ */, "") }; /'"$*"'/'
1999 read -r -p "press anything but contrl-c to delete"
2000 for entry
in $
(HISTTIMEFORMAT
='' history |
awk -v IGNORECASE
=1 '{ a=$1; sub(/^ *[^ ]+ */, "") }; /'"$*"'/ { print a }' |
tac); do
2006 # history without the date
2008 history "$@" | cut
-d' ' -f 7-
2011 ccomp
grep k ks ksu histrm
2015 # show make targets, via http://stackoverflow.com/questions/3063507/list-goals-targets-in-gnu-make
2016 make -qp |
awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}'
2028 # mkdir the last arg, cp the rest into it
2031 cp "${@:1:$#-1}" "${@: -1}"
2035 mv "${@:1:$#-1}" "${@: -1}"
2038 mkt
() { # mkdir and touch file
2040 mkdir
-p "$(dirname "$path")"
2044 # shellcheck disable=SC2032
2045 mkdir
() { command mkdir
-p "$@"; }
2048 # https://github.com/HenriWahl/Nagstamon/issues/357
2049 if ! pgrep
-f /usr
/bin
/dunst
>/dev
/null
; then
2052 /usr
/bin
/nagstamon
&
2057 screen
-RD -S profanity
2060 # i dont want to wait for konsole to exit...
2062 command prof
&>/dev
/null
&
2067 printf '\033[1A\033[K'; printf "%s\n" "$l"| ts
"%F %T" |
tee -a /p
/self-chat.log
2072 # cant use s because sudo -i doesnt work for passwordless sudo command
2075 sudo nmtui-connect
"$@"
2085 if shopt nullglob
>/dev
/null
; then
2099 # shellcheck disable=SC2024
2101 for f
in /var
/log
/exim
4/paniclog
/var
/log
/exim
4/*panic
; do
2103 if [[ -s $f ]]; then
2104 echo ================== $f =============
2105 s
tee -a /var
/log
/exim
4/$base-archive <$f
2113 ping() { command ping -O "$@"; }
2114 p8
() { ping "$@" 8.8.8.8; }
2115 p6
() { ping6
"$@" 2001:4860:4860::8888; }
2117 pkx
() { # package extract
2118 local pkg cached tmp f
2121 # shellcheck disable=SC2012
2122 cached
=$
(ls -t /var
/cache
/apt
/archives
/${pkg}_
* |
tail -n1 2>/dev
/null
) ||
:
2123 if [[ $cached ]]; then
2126 m aptitude download
$pkg ||
return 1
2128 tmp
=(*); f
=${tmp[0]} # only 1 expected
2137 tmpf
=$
(pgrep
-f "$*")
2138 mapfile
-t pids
<<<"$tmpf"
2141 # shellcheck disable=SC2128
2147 0) echo "no pid found" ;;
2156 help="Usage: psg [--help] GREP_ARGS
2157 grep ps and output in a nice format"
2158 if [[ $1 == --help ]]; then
2163 # final grep is because some commands tend to have a lot of trailing spaces
2164 y
=$
(echo "$x" |
grep -iP "$@" |
grep -o '.*[^ ]') ||
:
2166 echo "$x" |
head -n 1 ||
[[ $?
== 141 ]]
2171 pubip
() { curl
-4s https
://icanhazip.com
; }
2172 pubip6
() { curl
-6s https
://icanhazip.com
; }
2173 whatismyip
() { pubip
; }
2176 q
() { # start / launch a program in the backround and redir output to null
2180 # shellcheck disable=SC2120
2182 if [[ $HISTFILE ]]; then
2183 history -a # save history
2185 trap ERR
# this avoids a segfault
2187 # i had this redir, not sure why
2188 # exit "$@" 2>/dev/null
2191 # scp is insecure and deprecated.
2193 rsync
-Pt --inplace "$@"
2198 # available high ports are 1024-65535,
2199 # but lets skip things that are more likely to be in use
2202 print(secrets.SystemRandom().randrange(10002,65500))
2208 # shellcheck disable=SC1090 # expected to not follow
2218 # rsync, root is required to keep permissions right.
2219 # rsync --archive --human-readable --verbose --itemize-changes --checksum \(-ahvic\) \
2220 # --no-times --delete
2221 # basically, make an exact copy, use checksums instead of file times to be more accurate
2222 rsync
-ahvic --delete "$@"
2225 # like rlu, but dont delete files on the target end which
2226 # do not exist on the original end.
2230 # rl without preserving modification time.
2231 rsync
-ahvic --delete --no-t "$@"
2233 # [RSYNC_OPTS] HOST PATH
2235 # eg. rsu -opts frodo /testpath
2236 # relative paths will expanded with readlink -f.
2237 opts
=("${@:1:$#-2}") # 1 to last -2
2238 path
="${*:$#}" # last
2239 host="${*:$#-1:1}" # last -1
2240 if [[ $path == .
* ]]; then
2241 path
=$
(readlink
-f $path)
2243 m rsync
-ahvi --relative --no-implied-dirs "${opts[@]}" "$path" "root@$host:/";
2245 ccomp rsync rsd rsa rst rsu
2247 # find programs listening on a port
2250 # to figure out these args, i had to look at the man page from git version, as of 2022-04.
2251 s ss
-lpn state listening sport
= $port
2256 if [[ $
(systemctl is-active nscd ||
:) != inactive
]]; then
2261 hr
; s ss
-lpn sport
= 53
2262 if systemctl is-enabled dnsmasq
&>/dev
/null ||
[[ $
(systemctl is-active dnsmasq ||
:) != inactive
]]; then
2263 # this will fail is dnsmasq is failed
2264 hr
; m ser status dnsmasq |
cat ||
:
2266 hr
; echo $f:; ccat
$f
2267 hr
; m grr
'^ *(servers-file|server) *=|^ *no-resolv *$' /etc
/dnsmasq.conf
/etc
/dnsmasq.d
2268 f
=/etc
/dnsmasq-servers.conf
2269 hr
; echo $f:; ccat
$f
2272 echo /etc
/nsswitch.conf
:
2273 grep '^ *hosts:' /etc
/nsswitch.conf
2274 if systemctl is-enabled systemd-resolved
&>/dev
/null ||
[[ $
(systemctl is-active systemd-resolved ||
:) != inactive
]]; then
2275 hr
; m ser status systemd-resolved |
cat ||
:
2276 hr
; m resolvectl status |
cat
2284 if [[ $
(systemctl is-active nscd ||
:) != inactive
]]; then
2288 m sudo nscd
-i hosts
2290 if [[ $
(systemctl is-active dnsmasq ||
:) != inactive
]]; then
2291 m sudo systemctl restart dnsmasq
2293 if [[ $
(systemctl is-active systemd-resolved ||
:) != inactive
]]; then
2294 m sudo systemctl restart systemd-resolved
2296 if type -P resolvectl
&>/dev
/null
; then
2297 resolvectl flush-caches
2301 # add annoyingly long argument which should be the default
2303 sed -i --follow-symlinks "$@"
2308 # todo: test variable assignment with newlines here.
2309 # https://stackoverflow.com/questions/15783701/which-characters-need-to-be-escaped-when-using-bash
2311 # beware that it only works on the assumption that any special
2312 # characters in the input string are intended to be escaped, not to work
2313 # as special chacters.
2315 LC_ALL
=C
sed -e 's/[^a-zA-Z0-9,._+@%/-]/\\&/g; 1{$s/^$/""/}; 1!s/^/"/; $!s/$/"/'
2319 ssh fencepost
head -n 300 /gd
/gnuorg
/EventAndTravelInfo
/rms-current-trips.txt |
less
2328 command sudo
"$@" ||
return $?
2333 # I use a function because otherwise we cant use in a script,
2334 # cant assign to variable.
2336 # note: gksudo is recommended for X apps because it does not set the
2337 # home directory to the same, and thus apps writing to ~ fuck things up
2338 # with root owned files.
2340 if [[ $EUID != 0 ||
$1 == -* ]]; then
2341 # shellcheck disable=SC2034
2342 SUDOD
="$PWD" command sudo
-i "$@"
2348 sb
() { # sudo bash -c
2349 # use sb instead of s is for sudo redirections,
2350 # eg. sb 'echo "ok fine" > /etc/file'
2351 # shellcheck disable=SC2034
2353 sudo
-i bash
-c "$@"
2356 se
() { s urun
0077 "$@"; }
2359 safe_rename
() { # warn and dont rename if file exists.
2360 # mv -n exists, but it\'s silent
2361 if [[ $# != 2 ]]; then
2362 echo safe_rename error
: $# args
, need
2 >&2
2365 if [[ $1 != "$2" ]]; then # yes, we want to silently ignore this
2366 if [[ -e $2 ||
-L $2 ]]; then
2367 echo "Cannot rename $1 to $2 as it already exists."
2376 sudo
dd status
=none of
="$1"
2380 if type -p systemctl
&>/dev
/null
; then
2383 if (( $# >= 3 )); then
2384 echo iank
: ser expected
2 or
less arguments
2391 systemctl
-n 40 status
"$@"
2394 seru
() { systemctl
--user "$@"; }
2395 # like restart, but do nothing if its not already started
2398 if [[ $
(s systemctl
--no-pager show
-p ActiveState
$service ) == ActiveState
=active
]]; then
2399 systemctl restart
$service
2403 setini
() { # set a value in a .ini style file
2404 key
="$1" value
="$2" section
="$3" file="$4"
2405 if [[ -s $file ]]; then
2406 sed -ri -f - "$file" <<EOF
2407 # remove existing keys
2408 / *\[$section\]/,/^ *\[[^]]+\]/{/^\s*${key}[[:space:]=]/d}
2410 /^\s*\[$section\]/a $key=$value
2411 # from section to eof, do nothing
2412 /^\s*\[$section\]/,\$b
2413 # on the last line, if we haven't found section yet, add section and key
2425 sgo
() { # service go
2427 ser restart
$service ||
return 1
2428 if type -p systemctl
&>/dev
/null
; then
2434 # ignore services that dont exist
2435 if systemctl
cat $service &>/dev
/null
; then
2437 ser disable
$service
2443 systemctl list-unit-files | rg
"$@"
2448 # see https://savannah.gnu.org/maintenance/fsf/bash-style-guide/ for justifications
2449 local quotes others ret
2450 quotes
=2048,2068,2086,2206,2254
2451 others
=2029,2032,2033,2054,2164,
2452 shellcheck
-W 999 -x -e $quotes,$others "$@" || ret
=$?
2453 if (( ret
>= 1 )); then
2454 echo "A template comment to disable is now in clipboard. eg: # shellcheck disable=SC2206 # reason"
2455 cbs
"# shellcheck disable=SC"
2459 # sk with quotes. For checking scripts that we expect to take untrusted
2460 # input in order to verify we quoted vars.
2463 others
=2029,2033,2054,2164
2464 shellcheck
-W 999 -x -e $others "$@" ||
return $?
2469 for f
in $
(i s |
awk '$1 == "modified:" {print $2}'); do
2470 if istext
"$f" && [[ $
(head -n1 "$f" 2>/dev
/null
) == '#!/bin/bash'* ]]; then
2476 # sl: ssh, but firsh rsync our bashrc and related files to a special
2477 # directory on the remote host if needed.
2479 # Some environment variables and files need to be setup for this to work
2480 # (mine are set at the beginning of this file)
2482 # SL_FILES_DIR: Environment variable. Path to folder which should at
2483 # least have a .bashrc file or symlink. This dir will be rsynced to ~ on
2484 # remote hosts (top level symlinks are resolved) unless the host already
2485 # has a $SL_FILES_DIR/.bashrc. In that case, we assume it is a host you
2486 # control and sync files to separately and already has the ~/.bashrc you
2487 # want. The remote bash will also take its .inputrc config from this
2488 # folder (default of not existing is fine). Mine looks like this:
2489 # https://iankelling.org/git/?p=distro-setup;a=tree;f=sl/.iank
2491 # SL_INFO_DIR: Environment variable. This folder stores info about what
2492 # we detected on the remote system and when we last synced. It will be created
2493 # if it does not exist. Sometimes you may want to forget about a
2494 # remote system, you can use sl --rsync, or the function for that slr
2497 # SL_TEST_CMD: Env var. Meant to be used to vary the files synced
2498 # depending on the remote host. Run this string on the remote host the
2499 # first time sl is run (or if we run slr). The result is passed to
2500 # SL_TEST_HOOK. For example,
2501 # export SL_TEST_CMD=". /etc/os-release ; echo \${VERSION//[^a-zA-Z0-9]/}"
2503 # SL_TEST_HOOK: Env var. It is run as $SL_TEST_HOOK. This can set
2504 # $SL_FILES_DIR to vary the files synced.
2506 # SL_RSYNC_ARGS: Env var. String of arguments passed to rsync. For
2507 # example to exclude files within a directory. Note, excluded
2508 # files wont be deleted on rsync, you can add --delete-excluded
2509 # to the rsync command if that is desired.
2511 # SL_SSH_ARGS: Env var. Default arguments passed to ssh.
2513 # For when ~/.bashrc is already customized on the remote server, you
2514 # might find it problematic that ~/.bashrc is sourced for ALL ssh
2515 # commands, even in scripts. This paragraph is all about that. bash
2516 # scripts dont source ~/.bashrc, but call ssh in scripts and you get
2517 # ~/.bashrc. You dont want this. .bashrc is meant for interactive shells
2518 # and if you customize it, probably has bugs from time to time. This is
2519 # bad. Here's how I fix it. I have a special condition to "return" in my
2520 # .bashrc for noninteractive ssh shells (copy that code). Then use this
2521 # function or similar that passes LC_USEBASHRC=t when sshing and I want
2522 # my bashrc. Also, I don't keep most of my bashrc in .bashrc, i source a
2523 # separate file because even if I return early on, the whole file gets
2524 # parsed which can fail if there is a syntax error.
2526 # Background on LC_USEBASHRC var (no need to read if you just want to
2527 # use this function): env variables sent across ssh are strictly
2528 # limited, but we get LC_* at least in debian based machines, so we
2529 # just make that * be something no normal program would use. Note, on
2530 # hosts that dont allow LC_* I start an inner shell with LC_USEBASHRC
2531 # set, and the inner shell also allows running a nondefault
2532 # .bashrc. This means the outer shell still ran the default .bashrc,
2533 # but that is the best we can do.
2535 local now args remote dorsync haveinfo tmpa sshinfo tmp tmp2
type info_sec force_rsync \
2536 sync_dirname testcmd extra_info testbool files_sec sl_test_cmd sl_test_hook
2537 declare -a args tmpa
2541 # ssh [-1246Antivivisectionist] [-b bind_address] [-c cipher_spec] [-D [bind_address:]port]
2542 # [-E log_file] [-e escape_char] [-F configfile] [-I pkcs11] [-i identity_file] [-L address]
2543 # [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port] [-Q query_option]
2544 # [-R address] [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]] [user@]hostname
2547 # ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]
2548 # [-D [bind_address:]port] [-E log_file] [-e escape_char]
2549 # [-F configfile] [-I pkcs11] [-i identity_file]
2550 # [-J [user@]host[:port]] [-L address] [-l login_name] [-m mac_spec]
2551 # [-O ctl_cmd] [-o option] [-p port] [-Q query_option] [-R address]
2552 # [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]]
2555 if [[ $1 == --rsync ]]; then
2559 # shellcheck disable=SC2153 # intentional
2560 sl_test_cmd
=$SL_TEST_CMD
2561 # shellcheck disable=SC2153 # intentional
2562 sl_test_hook
=$SL_TEST_HOOK
2563 # shellcheck disable=SC2153 # intentional
2564 sl_rsync_args
=$SL_RSYNC_ARGS
2591 # note we dont support things like -4oOption
2592 -[46AaCfGgKkMNnqsTtVvXxYy
]*)
2595 -[bcDEeFIiJLlmOopQRSWw
]*)
2596 # -oOption etc is valid
2597 if (( ${#1} >= 3 )); then
2600 args
+=("$1" "$2"); shift 2
2609 if [[ ! $remote ]]; then
2610 echo $0: error hostname required
>&2
2615 if [[ ! $SL_INFO_DIR ]]; then
2616 echo 'error: missing SL_INFO_DIR env var' >&2
2622 tmpa
=($SL_INFO_DIR/???????????
"$remote")
2624 if [[ -e $sshinfo ]]; then
2625 if $force_rsync; then
2632 tmp
=${sshinfo[0]##*/}
2635 extra_info
=$
(cat $sshinfo)
2637 # we test for string to know ssh succeeded
2638 testbool
="test -e $SL_FILES_DIR/.bashrc -a -L .bashrc -a -v LC_USEBASHRC"
2639 testcmd
="if $testbool; then printf y; else printf n; fi"
2640 if ! tmp
=$
(LC_USEBASHRC
=y
command ssh "${args[@]}" "$remote" "$testcmd; $sl_test_cmd"); then
2641 echo failed sl
test. doing plain
ssh -v
2642 command ssh -v "${args[@]}" "$remote"
2644 if [[ $tmp == y
* ]]; then
2650 extra_info
="${tmp:1}"
2652 if [[ $sl_test_hook ]]; then
2653 RSYNC_RSH
="ssh ${args[*]}" $sl_test_hook "$extra_info" "$remote"
2656 if $haveinfo && [[ $type == b
]]; then
2658 read -r files_sec _
< <(find -L $SL_FILES_DIR -printf "%T@ %p\n" |
sort -nr ||
[[ $?
== 141 ||
${PIPESTATUS[0]} == 32 ]] )
2659 files_sec
=${files_sec%%.*}
2660 if (( files_sec
> info_sec
)); then
2666 sync_dirname
=${SL_FILES_DIR##*/}
2668 if [[ ! $SL_FILES_DIR ]]; then
2669 echo 'error: missing SL_FILES_DIR env var' >&2
2674 RSYNC_RSH
="ssh ${args[*]}" m rsync
-rptL --delete $sl_rsync_args $SL_FILES_DIR "$remote":
2676 if $dorsync ||
! $haveinfo; then
2677 sshinfo
=$SL_INFO_DIR/$EPOCHSECONDS$type"$remote"
2678 [[ -e $SL_INFO_DIR ]] || mkdir
-p $SL_INFO_DIR
2679 printf "%s\n" "$extra_info" >$sshinfo
2682 if [[ $type == b
]]; then
2683 if (( ${#@} )); then
2684 # Theres a couple ways to pass arguments, im not sure whats best,
2685 # but relying on bash 4.4+ escape quoting seems most reliable.
2686 command ssh "${args[@]}" "$remote" \
2687 LC_USEBASHRC
=t bash
-c '.\ '$sync_dirname'/.bashrc\;"\"\$@\""' bash
${@@Q}
2688 elif [[ ! -t 0 ]]; then
2689 # This case is when commands are being piped to ssh.
2690 # Normally, no bashrc gets sourced.
2691 # But, since we are doing all this, lets source it because we can.
2692 cat <(echo .
$sync_dirname/.bashrc
) - |
command ssh "${args[@]}" "$remote" LC_USEBASHRC
=t bash
2694 command ssh -t "${args[@]}" "$remote" LC_USEBASHRC
=t INPUTRC
=$sync_dirname/.inputrc bash
--rcfile $sync_dirname/.bashrc
2698 LC_USEBASHRC
=t
command ssh "${args[@]}" "$remote" ${@@Q}
2700 command ssh "${args[@]}" "$remote" LC_USEBASHRC
=t bash
2703 # this function inspired from https://github.com/Russell91/sshrc
2710 sl
-oControlMaster=no
-oControlPath=/ "$@"
2712 # kill off old shared socket then ssh
2714 m
ssh -O exit "$@" ||
[[ $?
== 255 ]]
2717 ccomp
ssh sl slr sss ssk
2720 if [[ $TERM == alacritty ||
$TERM == xterm-kitty
]]; then
2721 TERM
=xterm-256color LC_USEBASHRC
=t
command ssh "$@"
2723 LC_USEBASHRC
=t
command ssh "$@"
2729 # log with script. timing is $1.t and script is $1.s
2730 # -l to save to ~/typescripts/
2731 # -t to add a timestamp to the filenames
2732 local logdir do_stamp arg_base
2733 (( $# >= 1 )) ||
{ echo "arguments wrong"; return 1; }
2736 while getopts "lt" option
2739 l
) arg_base
=$logdir ;;
2742 echo error
: bad option
2747 shift $
((OPTIND
- 1))
2749 [[ -e $logdir ]] || mkdir
-p $logdir
2750 $do_stamp && arg_base
+=$
(date +%F.
%T
%z
)
2751 script -t $arg_base.s
2> $arg_base.t
2753 splay
() { # script replay
2754 #logRoot="$HOME/typescripts/"
2755 #scriptreplay "$logRoot$1.t" "$logRoot$1.s"
2756 scriptreplay
"$1.t" "$1.s"
2760 # sudo redo. be aware, this command may not work right on strange distros or earlier software
2761 if [[ $# == 0 ]]; then
2762 sudo
-E bash
-c -l "$(history -p '!!')"
2764 echo this
command redos last
history item. no argument is accepted
2769 # with -ll, less secure but faster.
2770 command srm
-ll "$@"
2775 ssh $1 "/tmp/${2##*/}" "$(printf "%q
\n" "${@:2}")"
2787 tclock
() { # terminal clock
2792 # this goes to full width
2793 #len=${1:-$((COLUMNS -7))}
2796 if (( x
== len
)); then
2798 d
="$(date +%l:%_M) "
2801 d
=$
(date +%l
:%M
:%_S
)
2805 for ((i
=0; i
<x
; i
++)); do
2806 if (( i
% 6 )); then
2824 # test existence / exists
2827 [[ -e "$x" ||
-L "$x" ]] || ret
=1
2833 # normally, i would just execute these commands in the function.
2834 # however, DEBUG is not inherited, so we need to run it outside a function.
2835 # And we want to run set -x afterwards to avoid spam, so we cram everything
2836 # in here, and then it will run after this function is done.
2837 # # set as array to satisfy shellcheck, but it is equivalent to setting it as non-array
2838 PROMPT_COMMAND
=('trap DEBUG; unset PROMPT_COMMAND; PS1="\w \$ "')
2841 PROMPT_COMMAND
=(prompt-command
)
2842 if [[ $TERM == *(screen
*|xterm
*|rxvt
*) ]]; then
2843 trap 'auto-window-title "$BASH_COMMAND"' DEBUG
2847 # prometheus node curl
2850 host=${1:-127.0.0.1}
2851 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
2854 tx
() { # toggle set -x, and the prompt so it doesnt spam
2855 if [[ $
- == *x
* ]]; then
2864 # show all processes in the network namespace $1.
2865 # blank entries appear to be subprocesses/threads
2869 sudo
find -L /proc
/[1-9]*/task
/*/ns
/net
-samefile /run
/netns
/$netns | cut
-d/ -f5 | \
2871 x
=$
(ps
-w --no-headers -p $l);
2872 if [[ $x ]]; then echo "$x"; else echo $l; fi;
2876 if ! s ip netns list |
grep -Fx nonet
&>/dev
/null
; then
2877 s ip netns add nonet
2879 sudo
-E env
/sbin
/ip netns
exec nonet sudo
-E -u iank
/bin
/bash
2882 m
() { printf "%s\n" "$*"; "$@"; }
2884 # update file. note: duplicated in mail-setup.
2885 # updates $ur u result to true or false
2886 # updates $reload to true if file updated is in /etc/systemd/system
2888 local tmp tmpdir dest
="$1"
2889 local base
="${dest##*/}"
2890 local dir
="${dest%/*}"
2891 if [[ $dir != "$base" ]]; then
2892 # dest has a directory component
2895 # shellcheck disable=SC2034 # see comment at top of function
2897 tmpdir
="$(mktemp -d)"
2898 cat >$tmpdir/"$base"
2899 tmp
=$
(rsync
-ic $tmpdir/"$base" "$dest")
2901 printf "%s\n" "$tmp"
2902 # shellcheck disable=SC2034 # see comment at top of function
2904 if [[ $dest == /etc
/systemd
/system
/* ]]; then
2905 # shellcheck disable=SC2034 # see comment at top of function
2914 if type -p uprecords
&>/dev
/null
; then
2922 for x
in "$@"; do virsh destroy
"$x"; virsh undefine
"$x"; done
2930 sudo virsh dumpxml
$vm |
sed -r "s/(<listen.*address=')([^']+)/\1$ip/" | \
2931 sed -r "s/listen='[^']+/listen='$ip/"> $t
2932 sudo virsh undefine
$vm
2933 sudo virsh define
$t
2938 vm-set-listen
$1 0.0.0.0
2943 vm-set-listen
$1 127.0.0.1
2948 interfaces
=$
(iw dev |
awk '$1 == "Interface" {print $2}')
2949 for i
in $interfaces; do
2950 echo "myiwscan: considering $i"
2951 # find input, copy to pattern space, when we find the first field, print the copy in different order without newlines.
2952 # instead of using labels, we could just match a line and group, eg: /signal:/,{s/signal:(.*)/\1/h}
2953 sudo iw dev
$i scan |
sed -rn "
2954 s/^\Wcapability: (.*)/\1/;Ta;h;b
2955 :a;s/^\Wsignal: -([^.]+).*/\1/;Tb;H;b
2956 # padded to min width of 20
2957 :b;s/\WSSID: (.*)/\1 /;T;s/^(.{20}(.*[^ ])?) */\1/;H;g;s/(.*)\n(.*)\n(.*)/\2 \3 \1/gp;b
2962 # Run script by copying it to a temporary location first,
2963 # and changing directory, so we don't have any open
2964 # directories or files that could cause problems when
2981 # spark 1 5 22 13 53
2985 # Copyright (c) Zach Holman, https://zachholman.com
2986 # https://github.com/holman/spark
2988 # As of 2022-10-28, I reviewed github forks that had several newer
2989 # commits, none had anything interesting. I did a little refactoring
2990 # mostly to fix emacs indent bug.
2992 # Generates sparklines.
2995 if [ "X$1" = "X-n" ]; then
3009 # find min/max values
3010 local min
=0xffffffff max
=0
3014 # on Linux (or with bash4) we could use `printf %.0f $n` here to
3015 # round the number but that doesn't work on OS X (bash3) nor does
3016 # `awk '{printf "%.0f",$1}' <<< $n` work, so just cut it off
3018 (( n
< min
)) && min
=$n
3019 (( n
> max
)) && max
=$n
3020 numbers
=$numbers${numbers:+ }$n
3024 local ticks
=(▁ ▂ ▃ ▄ ▅ ▆ ▇ █
)
3026 # use a high tick if data is constant
3027 (( min
== max
)) && ticks
=(▅ ▆
)
3030 f
=$
(( ( (max-min
) <<8)/( tc - 1) ))
3035 _spark_echo -n ${ticks[$(( (((n-min)<<8)/f) ))]}
3040 pdfwc() { local f; for f; do echo "$f" "$(pdfinfo "$f" | awk '/^Pages:/ {print $2}')"; done }
3043 # nvm install script appended this to my .bashrc. I dont want to run it all the time,
3044 # so put it in a function.
3046 export NVM_DIR="$HOME/.nvm"
3047 # shellcheck disable=SC1091 # may not exist, & third party
3048 [ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh" # This loads nvm
3049 # shellcheck disable=SC1091 # may not exist, & third party
3050 [ -s "$NVM_DIR/bash_completion" ] && source "$NVM_DIR/bash_completion" # This loads nvm bash_completion
3055 if date -d 'february 29' &>/dev/null; then
3065 if [[ -e /sys/class/power_supply/AC/online && $(</sys/class/power_supply/AC/online) == 0 ]]; then
3072 # make vim work with my light colortheme terminal.
3074 if [[ -e ~/.vimrc ]]; then
3077 command vim -c ':colorscheme peachpuff' "$@"
3081 # ls count. usage: pass a directory, get the number of files.
3082 # https://unix.stackexchange.com/questions/90106/whats-the-most-resource-efficient-way-to-count-how-many-files-are-in-a-director
3084 # shellcheck disable=SC2790 disable=SC2012 # intentional
3088 # run then notify. close notification after the next prompt.
3091 dunstify -u critical -h string:x-dunst-stack-tag:profanity "$*"
3092 _psrun=(dunstctl close-all)
3095 dunstify -u critical -h string:x-dunst-stack-tag:profanity n
3096 _psrun=(dunstctl close-all)
3102 inotifywait -m "$dir" -e create -e moved_to | while read -r _ _ file; do
3116 if ! type -p sponge &>/dev/null; then
3117 echo "$0: error: missing dependency: sudo apt install moreutils" >&2
3122 echo "adding header to $f"
3123 if [[ -s $f ]]; then
3128 cat - "${f_maybe[@]}" <<EOF | sponge "$f"
3129 The following is the GNU All-permissive License as recommended in
3130 <https://www.gnu.org/licenses/license-recommendations.en.html>
3132 Copyright (C) $(date +%Y) Free Software Foundation <sysadmin@fsf.org>
3134 Copying and distribution of this file, with or without modification,
3135 are permitted in any medium without royalty provided the copyright
3136 notice and this notice are preserved. This file is offered as-is,
3137 without any warranty.
3139 Contributions are welcome. See <https://savannah.gnu.org/maintenance/fsf/>.
3145 # note, there is also the tool gron which is meant for this, but
3146 # this is good enough to not bother installing another tool
3148 # https://stackoverflow.com/questions/59700329/how-to-print-path-and-key-values-of-json-file-using-jq
3149 jq --stream -r 'select(.[1]|scalars!=null) | "\(.[0]|join(".")): \(.[1]|tojson)"' "$@"
3153 "$@" |& ts || return $?
3160 if $use_color && type -p tput &>/dev/null; then
3161 # this is nice for a dark background terminal:
3162 # https://github.com/trapd00r/LS_COLORS
3163 # I would like if there was something similar for light.
3165 # the default bold green is too light.
3166 # this explains the codes: https://gist.github.com/thomd/7667642
3167 export LS_COLORS=ex=1
3169 term_bold="$(tput bold)"
3170 term_red="$(tput setaf 1)"
3171 term_green="$(tput setaf 2)"
3172 # shellcheck disable=SC2034 # expected
3173 term_yellow="$(tput setaf 3)"
3174 term_purple="$(tput setaf 5)"
3175 term_nocolor="$(tput sgr0)" # no font attributes
3177 # unused so far. commented for shellcheck
3178 # term_underl="$(tput smul)"
3179 # term_blue="$(tput setaf 4)"
3180 # term_cyan="$(tput setaf 6)"
3182 # Try to keep environment pollution down, EPA loves us.
3183 unset safe_term match_lhs use_color
3188 if [[ $- == *i* ]]; then
3193 if [[ $EUID == 1000 ]]; then
3200 # this needs to come before next ps1 stuff
3201 # this stuff needs bash 4, feb 2009,
3202 # old enough to no longer condition on $BASH_VERSION anymore
3206 if [[ $- == *i* ]] && [[ ! $LC_INSIDE_EMACS ]]; then
3208 bind -m vi-command B:shell-backward-word
3209 bind -m vi-command W:shell-forward-word
3212 if [[ $SSH_CLIENT || $SUDO_USER ]]; then
3213 unset PROMPT_DIRTRIM
3217 # emacs terminal has problems if this runs slowly,
3218 # so I've thrown a bunch of things at the wall to speed it up.
3220 local return=$? # this MUST COME FIRST
3221 local ps_char ps_color
3224 if [[ $HISTFILE ]]; then
3225 history -a # save history
3229 0) ps_color="$term_purple"
3232 *) ps_color="$term_green"
3233 ps_char="$return \\$"
3236 if [[ ! -O . ]]; then # not owner
3237 if [[ -w . ]]; then # writable
3238 ps_color="$term_bold$term_red"
3240 ps_color="$term_bold$term_green"
3244 # faster than sourceing the file im guessing
3245 if [[ -e /dev/shm/iank-status && ! -e /tmp/quiet-status ]]; then
3246 eval "$(< /dev/shm/iank-status)"
3248 if [[ $MAIL_HOST && $MAIL_HOST != "$HOSTNAME" ]]; then
3249 ps_char="@ $ps_char"
3252 if [[ $(jobs -p) ]]; then
3257 # allow a function to specify a command to run after we run the next
3258 # command. Use case: a function makes a persistent notification. If
3259 # we happen to be using that terminal, we can just keep working by
3260 # entering our next command, even a noop in order to dismiss the
3261 # notification, instead of having to explicitly dismiss it.
3262 if [[ ${_psrun[*]} ]]; then
3263 if (( _psrun_count >= 1 )); then
3269 _psrun_count=$(( _psrun_count + 1 ))
3275 # We could test if sudo is active with sudo -nv
3276 # but then we get an email and log of lots of failed sudo commands.
3277 # We could turn those off, but seems better not to.
3278 if [[ $EUID != 0 ]] && [[ $DID_SUDO ]]; then
3279 psudo="\[$term_bold$term_red\]s\[$term_nocolor\] "
3281 if [[ ! $HISTFILE ]]; then
3282 ps_char="NOHIST $ps_char"
3284 PS1="${PS1%"${PS1#*[wW]}"} $jobs_char$psudo\[$ps_color\]$ps_char\[$term_nocolor\] "
3286 # copy of what is automatically added by guix.
3287 # adds [env] to PS1 if GUIX_ENVIRONMENT is set and PS1 contains '$';
3288 if [ -n "$GUIX_ENVIRONMENT" ]; then
3289 if [[ $PS1 =~ (.*)"\\$" ]]; then
3290 PS1="${BASH_REMATCH[1]} [env]\\\$ "
3295 # set titlebar. instead, using more advanced
3297 #echo -ne "$_title_escape $HOSTNAME ${PWD/#$HOME/~} \007"
3299 PROMPT_COMMAND=(prompt-command)
3301 if [[ $TERM == screen* ]]; then
3302 _title_escape="\033]..2;"
3304 # somme sites recommend this, i dunno what the diff is.
3305 #_title_escape="\033]30;"
3306 _title_escape="\033]0;"
3309 # make the titlebar be the last command and the current directory.
3310 auto-window-title () {
3313 # These are some checks to help ensure we dont set the title at
3314 # times that the debug trap is running other than the case we
3315 # want. Some of them might not be needed.
3316 if (( ${#FUNCNAME[@]} != 1 || ${#BASH_ARGC[@]} != 2 || BASH_SUBSHELL != 0 )); then
3319 if [[ $1 == prompt-command ]]; then
3322 echo -ne "$_title_escape ${PWD/#$HOME/~} "
3327 # note, this wont work:
3328 # x=$(mktemp); cp a $x
3329 # I havnt figured out why, bigger fish to fry.
3332 # condition from the screen man page i think.
3333 # note: duplicated in tx()
3334 if [[ $TERM == *(screen*|xterm*|rxvt*) ]]; then
3335 trap 'auto-window-title "$BASH_COMMAND"' DEBUG
3342 # * stuff that makes sense to be at the end
3348 if [[ -s "$HOME/.rvm/scripts/rvm" ]]; then
3349 # shellcheck disable=SC1091
3350 source "$HOME/.rvm/scripts/rvm"
3353 # I had this idea to start a bash shell which would run an initial
3354 # command passed through this env variable, then continue on
3355 # interactively. But the use case I had in mind went away.
3357 # if [[ $MY_INIT_CMD ]]; then
3358 # "${MY_INIT_CMD[@]}"
3362 # ensure no bad programs appending to this file will have an affect