710 lines
24 KiB
Bash
710 lines
24 KiB
Bash
#!/usr/bin/env bash
|
|
# executed by bash(1) for non-login shells.
|
|
|
|
# ==============================
|
|
# FUNCTIONS
|
|
# ==============================
|
|
|
|
# ==============================
|
|
# System
|
|
# ==============================
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# pass declared functions to sudo, /!\ aliases in the function will not work
|
|
sudof() {
|
|
|
|
Help() {
|
|
cat <<- HEREDOC
|
|
|
|
Pass declared functions as command to sudo bash.
|
|
Syntax: sudof [-h] <functionName> [<options/arguments>]
|
|
options:
|
|
-h Print this Help.
|
|
|
|
HEREDOC
|
|
}
|
|
while getopts ":h" option; do
|
|
case $option in
|
|
h) Help; return 0 ;;
|
|
\?) echo -e "Unknown option: -$OPTARG \n" >&2; Help; return 1;;
|
|
: ) echo -e "Missing argument for -$OPTARG \n" >&2; Help; return 1;;
|
|
* ) echo -e "Unimplemented option: -$option \n" >&2; Help; return 1;;
|
|
esac
|
|
done
|
|
|
|
local TMPFUNC=$(declare -f "$1")
|
|
local TMPCMD=${@:1}
|
|
sudo bash -c "$TMPFUNC; $TMPCMD"
|
|
}
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# Pretty print dependencies from a package with dpkg
|
|
dpkg-debdep() {
|
|
dpkg --info "$1" | \
|
|
awk 'BEGIN{print "Depends:"} \
|
|
/Depends: / { gsub("Depends: ", ""); \
|
|
n=split($0,deps,","); \
|
|
for(i=1;i<=n;i++) print deps[i] \
|
|
}'
|
|
}
|
|
|
|
# ==============================
|
|
# Terminal
|
|
# ==============================
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# set of functions for marks/jump, MARKPATH created/exported in 01.env.bashrc
|
|
mark() { ln -s "$(pwd)" "$MARKPATH/$1"; }
|
|
unmark() { rm -i "$MARKPATH/$1"; }
|
|
marks() { ls -l "$MARKPATH" | sed 's/ / /g' | cut -d' ' -f9- | sed 's/ -/\t-/g' && echo; }
|
|
jump() { cd -P "$MARKPATH/$1" 2>/dev/null || echo "No such mark: $1"; }
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# pipe to hl only if you are in a tty and the output is not piped or redirected
|
|
if command -v hl 1> /dev/null; then
|
|
hlauto() {
|
|
if [ -t 1 ]; then
|
|
hl "$1"
|
|
else
|
|
cat -
|
|
fi
|
|
}
|
|
fi
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# full page of \n for the clear alias
|
|
pgdown() {
|
|
printf '\n%.0s' $(eval echo {1..$(( $(tput lines) - 1 ))})
|
|
}
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# clear teminal and TMUX history and get to the bottom line
|
|
c() {
|
|
echo -en "\ec"; pgdown
|
|
if [[ -n $TMUX_PANE ]]; then
|
|
tmux clear-history -t "$TMUX_PANE"
|
|
fi
|
|
}
|
|
|
|
# ==============================
|
|
# Utils
|
|
# ==============================
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# backup files/directories/braced-list with revisions
|
|
backupcp() { mkdir $HOME/.backups/; cp -r --backup=t "$1" "$HOME"/.backups/; }
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# mkdir with sub-dirs and change of pwd
|
|
md() { mkdir -pv "$1" && cd "$1"; }
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# list almost all services units (except user disabled) with state color
|
|
lservices() {
|
|
Help() {
|
|
cat <<- HEREDOC
|
|
|
|
List all Systemd services units.
|
|
Simplified and colorful.
|
|
|
|
Syntax: lservices [-h] [-x] [<username>]
|
|
Output: ServiceName UID STATE DESCRIPTION
|
|
options:
|
|
-h Print this Help.
|
|
-x Copy the list to Clipboard with xclip.
|
|
-p Disable the pager feature.
|
|
<username> [root] display --system services,
|
|
[other] display --user services,
|
|
[empty] default to current user.
|
|
|
|
HEREDOC
|
|
}
|
|
|
|
local OPTIND=0
|
|
while getopts ":hxp" option; do
|
|
case $option in
|
|
h) Help; return 0 ;;
|
|
x) local _XCLIP=1;;
|
|
p) local _NOPAGER=1;;
|
|
\?) echo -e "Unknown option: -$OPTARG \n" >&2; Help; return 1;;
|
|
: ) echo -e "Missing argument for -$OPTARG \n" >&2; Help; return 1;;
|
|
* ) echo -e "Unimplemented option: -$option \n" >&2; Help; return 1;;
|
|
esac
|
|
done
|
|
shift $((OPTIND-1))
|
|
|
|
if [[ -z $1 ]]; then
|
|
local _UID=$(id -u)
|
|
else
|
|
local _UID=$(id -u $1)
|
|
fi
|
|
|
|
if [[ "$_UID" == "0" ]]; then
|
|
local _OUT=$(sudo systemctl list-units --system -q --plain --full --no-pager -t service)
|
|
elif [[ "$_UID" == "$(id -u)" ]]; then
|
|
local _OUT=$(systemctl list-units --user -q --plain --full --no-pager -t service)
|
|
else
|
|
local _OUT=$(sudo machinectl -q shell --uid="$_UID" .host /usr/bin/systemctl list-units --user -q --plain --full --no-pager -t service)
|
|
fi
|
|
|
|
if [[ $_XCLIP == 1 ]]; then
|
|
echo -e "${_OUT}" | xclip -selection clipboard
|
|
fi
|
|
|
|
local _OUT=$(echo "$_OUT" | awk -v uid=$_UID ' \
|
|
BEGIN {
|
|
red = "\033[1;31m"
|
|
green = "\033[1;32m"
|
|
yellow = "\033[1;33m"
|
|
blue = "\033[1;36m"
|
|
reset = "\033[0m"
|
|
|
|
map["running"] = green
|
|
map["exited"] = yellow
|
|
map["failed"] = red
|
|
}
|
|
match($0,/^(.*)\.service(\s*)loaded\s[a-z]+\s([a-z]+)(\s.*)$/,a) {
|
|
status = a[3]
|
|
if ( status in map )
|
|
$0 = blue a[1] a[2] reset " " uid " " map[status] status reset a[4]
|
|
else
|
|
$0 = blue a[1] a[2] reset " " uid " " a[3] a[4]
|
|
}
|
|
{ print } '
|
|
)
|
|
|
|
if [[ $_NOPAGER == 1 ]]; then
|
|
echo -e "${_OUT}"
|
|
else
|
|
echo -e "${_OUT}" | less --ignore-case --LONG-PROMPT --mouse --RAW-CONTROL-CHARS --tilde --use-color --quit-if-one-screen
|
|
fi
|
|
|
|
if [[ $_XCLIP == 1 ]]; then
|
|
echo "List copied in the system clipboard!"
|
|
fi
|
|
}
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# bat/cat-like with no comments
|
|
if command -v bat 1> /dev/null; then
|
|
batl() {
|
|
bat -pp --color always "$@" \
|
|
| sed -E -e '1b;/^(\x1B\[[0-9;]+m\s*\x1B\[[0-9;]+m\x1B\[[0-9;]+m)?(\s+)?(\x1B\[[0-9;]+m)?(#|\")/d' \
|
|
| bat --decorations never --pager "less --ignore-case --status-column --line-numbers --quiet --tilde --use-color --quit-if-one-screen --RAW-CONTROL-CHARS"
|
|
}
|
|
fi
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# custom alternative to ls that pipe to fzf-tmux or fzf
|
|
lf() {
|
|
Help() {
|
|
cat <<- HEREDOC
|
|
|
|
A custom alternative to ls that pipe to fzf-tmux or fzf
|
|
Accept only the first path submitted (Default=.)
|
|
|
|
Syntax: lf [-h] [-a] [-e] [-o] [-t -l level] [<path>]
|
|
options:
|
|
-h Print this Help.
|
|
-a Display hidden files
|
|
-e Sort by extension
|
|
-o Sort by oldest
|
|
-t Tree mode
|
|
-l num Tree level, default=2
|
|
|
|
HEREDOC
|
|
}
|
|
|
|
local _type="list"
|
|
local _filter="visible"
|
|
local _by="name"
|
|
local _lvl=""
|
|
local _fzf_opt="--preview-window down:5:wrap"
|
|
|
|
local OPTIND=0
|
|
while getopts ":haeotl:" option; do
|
|
case $option in
|
|
h) Help; return 0 ;;
|
|
a) local _all="-a"
|
|
local _filter="all";;
|
|
e) local _sort="--sort=extension"
|
|
local _by="ext" ;;
|
|
o) local _sort="--sort=oldest"
|
|
local _by="oldest" ;;
|
|
t) local _tree="-T"
|
|
local _type="tree"
|
|
local _fzf_opt="--keep-right --preview-window down:2:wrap"
|
|
local _lvl=", with 2 level," ;;
|
|
l) local _level="-L ${OPTARG}"
|
|
local _lvl=", with ${OPTARG} level," ;;
|
|
\?) echo -e "Unknown option: -$OPTARG \n" >&2; Help; return 1;;
|
|
: ) echo -e "Missing argument for -$OPTARG \n" >&2; Help; return 1;;
|
|
* ) echo -e "Unimplemented option: -$option \n" >&2; Help; return 1;;
|
|
esac
|
|
done
|
|
shift $((OPTIND-1))
|
|
|
|
if [[ -f "/usr/bin/tmux" || -f "/usr/local/bin/tmux" ]]; then
|
|
local _fzfCmd="fzf-tmux -p 95%,75%"
|
|
else
|
|
local _fzfCmd="fzf"
|
|
fi
|
|
|
|
if [ -z "$1" ]; then
|
|
local _location="$(realpath -sq "$PWD" 2>&1)"
|
|
elif [ -z "$2" ]; then
|
|
local _location="$(realpath -sq "$1" 2>&1)"
|
|
else
|
|
echo "Error: Invalid number of paths"
|
|
Help
|
|
return 0
|
|
fi
|
|
|
|
local _localizer="awk -v loc=\"$_location/\" '{print \"\\\"\" loc \$0 \"\\\"\"}'"
|
|
local _oneliner="sed -E -e 's/\s->\s.+//g' \
|
|
| awk '{\$1=\$2=\$3=\$4=\$5=\$6=\$7=\"\"; \$0=\$0; \$1=\$1; print \$0}' \
|
|
| sed -E -e 's/^[^[:digit:][:alpha:]_.]*\s//g' \
|
|
| awk -v loc=\"$_location/\" '{print \"\\\"\" loc \$0 \"\\\"\"}' \
|
|
| xargs -d \"\n\""
|
|
if [[ "$_type" == "tree" ]]; then
|
|
local _localizer="awk '{print \"\\\"\" \$0 \"\\\"\"}'"
|
|
local _oneliner="cat"
|
|
fi
|
|
|
|
exa -bghHl $_all $_sort $_tree $_level --icons --git --color always --group-directories-first --time-style=long-iso "$_location" 2>&1 \
|
|
| ${_fzfCmd} -p 95%,75% --multi --reverse --ansi --tabstop 2 --header-lines 1 \
|
|
--prompt "A $_type$_lvl of $_filter elements sorted by $_by in \"$_location\" > " \
|
|
$_fzf_opt --bind ctrl-a:select-all,ctrl-d:deselect-all,ctrl-t:toggle-all,ctrl-p:toggle-preview \
|
|
--preview "for line in {+}; do echo \"\$line\"; done \
|
|
| sed -E -e 's/\s->\s.+//g' \
|
|
| awk '{\$1=\$2=\$3=\$4=\$5=\$6=\$7=\"\"; \$0=\$0; \$1=\$1; print \$0}' \
|
|
| sed -E -e 's/^[^[:digit:][:alpha:]_.]*\s//g' \
|
|
| $_localizer \
|
|
| xargs -d \"\n\"" \
|
|
| eval "$_oneliner"
|
|
}
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# find file/symlinks or directories with fd and fzf, use a regex pattern and an optionnal location
|
|
fdf() {
|
|
local array=( fd exa fzf bat )
|
|
for cmd in "${array[@]}"; do
|
|
if [[ -z $(command -v $cmd) ]]; then
|
|
echo 'function requirements: $cmd could not be found: sudo apt install fd-find exa fzf bat'
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
Help() {
|
|
cat <<- HEREDOC
|
|
|
|
Filesystem search shortcuts with fd, fzf bat and exa
|
|
|
|
Syntax: fdf [-h] [-d] [-p] [-e] "<regex_query>" [<location>]
|
|
options:
|
|
-h Print this Help.
|
|
-d search directories only (defaut to files & symlinks)
|
|
-p preview in fzf (bat for files and exa tree for dirs)
|
|
-e output results with exa
|
|
|
|
HEREDOC
|
|
}
|
|
|
|
local _fdfindType="-tf -tl"
|
|
if [[ -f "/usr/bin/tmux" || -f "/usr/local/bin/tmux" ]]; then
|
|
local _fzfCmd="fzf-tmux"
|
|
else
|
|
local _fzfCmd="fzf"
|
|
fi
|
|
local _previewCdm="bat --style=numbers --color=always --line-range :150 {}"
|
|
local _xargs="cat"
|
|
|
|
local OPTIND=0
|
|
while getopts ":hdpe" option; do
|
|
case $option in
|
|
h) Help; return 0 ;;
|
|
d) local _fdfindType="-td"
|
|
local _exaType="-d"
|
|
local _fzfHeaderType="dir"
|
|
local _previewCdm="exa -bhlaTL 2 --icons --color always --group-directories-first --no-permissions --time-style=iso {}" ;;
|
|
p) local _fzfCmd="fzf"
|
|
local _preview=$_previewCdm ;;
|
|
e) local _xargs="xargs -r exa -abghHl --icons --color always --group-directories-first --time-style=long-iso" ;;
|
|
\?) echo -e "Unknown option: -$OPTARG \n" >&2; Help; return 1;;
|
|
: ) echo -e "Missing argument for -$OPTARG \n" >&2; Help; return 1;;
|
|
* ) echo -e "Unimplemented option: -$option \n" >&2; Help; return 1;;
|
|
esac
|
|
done
|
|
shift $((OPTIND-1))
|
|
if [ -z "$1" ]; then
|
|
echo "Error: fdf needs a <regex_query>"
|
|
Help
|
|
return 0
|
|
fi
|
|
|
|
if [ -z "$2" ]; then
|
|
local _searchPath="$(realpath -sq "$PWD" 2>&1)"
|
|
else
|
|
local _searchPath="$(realpath -sq "$2" 2>&1)"
|
|
fi
|
|
|
|
fdfind -0aH $_fdfindType ^$1\$ "$_searchPath" | xargs -r -0 exa $_exaType --colour=always \
|
|
| $_fzfCmd -m --reverse --ansi --keep-right --bind ctrl-a:select-all,ctrl-d:deselect-all,ctrl-t:toggle-all --header "^$1\$ $_fzfHeaderType in \"$_searchPath\"" --preview "$_preview" | eval "$_xargs"
|
|
}
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# better listing for all tcp/udp sockets
|
|
ssfull() {
|
|
if [[ -f "/usr/bin/tmux" || -f "/usr/local/bin/tmux" ]]; then
|
|
local _fzfCmd="fzf-tmux"
|
|
else
|
|
local _fzfCmd="fzf"
|
|
fi
|
|
ss -Haptun --cgroup 2>&1 \
|
|
| awk '{gsub(/cgroup:/,"- - cgroup:",$7);if($7 =="")print $0" - - -";else print $0;}' \
|
|
| awk '{
|
|
gsub(/,fd=.+,pid=/,",",$7);gsub(/users:|\(|\)|,fd=[0-9]+/,"",$7);gsub(/,pid=/," ",$7);
|
|
gsub(/.+\/|cgroup:/,"",$8);
|
|
gsub(/.+\/|cgroup:/,"",$9);
|
|
if(match($5, /^.+%[^\]]+:.+$/))localip = gensub(/^(.*[0-9\]*])%.+:[0-9*]{1,5}$/,"\\1","g",$5);else localip = gensub(/^(.*):[0-9*]{1,5}$/,"\\1","g",$5);
|
|
if(match($5, /^.+%[^\]]+:.+$/))localindex = gensub(/^.+%([^\]]+):.+$/,"\\1","g",$5);else localindex = "-";
|
|
localport = gensub(/^.*:([^:]*)$/,"\\1","g",$5);
|
|
if(match($6, /^.+%[^\]]+:.+$/))peerip = gensub(/^(.*[0-9\]*])%.+:[0-9*]{1,5}$/,"\\1","g",$6);else peerip = gensub(/^(.*):[0-9*]{1,5}$/,"\\1","g",$6);
|
|
if(match($6, /^.+%[^\]]+:.+$/))peerindex = gensub(/^.+%([^\]]+):.+$/,"\\1","g",$6);else peerindex = "-";
|
|
peerport = gensub(/^.*:([^:]*)$/,"\\1","g",$6);
|
|
stategroup = "";
|
|
if(match($2, /^ESTAB$/))stategroup = "1-ESTABL";
|
|
if(match($2, /^SYN-SENT$/))stategroup = "1-ESTABL";
|
|
if(match($2, /^SYN-RECV$/))stategroup = "1-ESTABL";
|
|
if(match($2, /^FIN-WAIT-1$/))stategroup = "2-CLOSIN";
|
|
if(match($2, /^FIN-WAIT-2$/))stategroup = "2-CLOSIN";
|
|
if(match($2, /^CLOSE-WAIT$/))stategroup = "2-CLOSIN";
|
|
if(match($2, /^LAST-ACK$/))stategroup = "2-CLOSIN";
|
|
if(match($2, /^CLOSING$/))stategroup = "2-CLOSIN";
|
|
if(match($2, /^TIME-WAIT$/))stategroup = "3-WAITIN";
|
|
if(match($2, /^LISTEN$/))stategroup = "0-LISTEN";
|
|
if(match($2, /^UNCONN$/))stategroup = "0-LISTEN";
|
|
if(stategroup =="")stategroup = "-";
|
|
if($1 =="tcp" || $1 == "udp")print stategroup,$1,localip,localindex,localport,peerip,peerindex,peerport,$7,$8,$9;
|
|
}' \
|
|
| sort -k1,1 -k3,3 -k4,4 -k6,6n \
|
|
| awk 'BEGIN{print "StateGroup Protocol LocalAddr LocalIndex LocalPort PeerAddr PeerIndex PeerPort Process PID Cgroup"}1' \
|
|
| column -t \
|
|
| $_fzfCmd --multi --reverse --ansi --keep-right --tabstop 2 --header-lines 1 --prompt "List of all tcp/udp sockets > " --bind ctrl-a:select-all,ctrl-d:deselect-all,ctrl-t:toggle-all
|
|
}
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# better listing for listening tcp/udp sockets
|
|
sslisten() {
|
|
if [[ -f "/usr/bin/tmux" || -f "/usr/local/bin/tmux" ]]; then
|
|
local _fzfCmd="fzf-tmux"
|
|
else
|
|
local _fzfCmd="fzf"
|
|
fi
|
|
ss -Hlptun --cgroup 2>&1 \
|
|
| awk '{gsub(/cgroup:/,"- - cgroup:",$7);if($7 =="")print $0" - - -";else print $0;}' \
|
|
| awk '{
|
|
gsub(/,fd=.+,pid=/,",",$7);gsub(/users:|\(|\)|,fd=[0-9]+/,"",$7);gsub(/,pid=/," ",$7);
|
|
gsub(/.+\/|cgroup:/,"",$8);
|
|
gsub(/.+\/|cgroup:/,"",$9);
|
|
if(match($5, /^.+%[^\]]+:.+$/))localip = gensub(/^(.*[0-9\]*])%.+:[0-9*]{1,5}$/,"\\1","g",$5);else localip = gensub(/^(.*):[0-9*]{1,5}$/,"\\1","g",$5);
|
|
if(match($5, /^.+%[^\]]+:.+$/))localindex = gensub(/^.+%([^\]]+):.+$/,"\\1","g",$5);else localindex = "-";
|
|
localport = gensub(/^.*:([^:]*)$/,"\\1","g",$5);
|
|
if(match($6, /^.+%[^\]]+:.+$/))peerip = gensub(/^(.*[0-9\]*])%.+:[0-9*]{1,5}$/,"\\1","g",$6);else peerip = gensub(/^(.*):[0-9*]{1,5}$/,"\\1","g",$6);
|
|
if(match($6, /^.+%[^\]]+:.+$/))peerindex = gensub(/^.+%([^\]]+):.+$/,"\\1","g",$6);else peerindex = "-";
|
|
peerport = gensub(/^.*:([^:]*)$/,"\\1","g",$6);
|
|
stategroup = "";
|
|
if(match($2, /^LISTEN$/))stategroup = "LISTENING";
|
|
if(match($2, /^UNCONN$/))stategroup = "LISTENING";
|
|
if(stategroup =="")stategroup = "-";
|
|
if($1 =="tcp" || $1 == "udp")print stategroup,$1,localip,localindex,localport,peerip,peerindex,peerport,$7,$8,$9;
|
|
}' \
|
|
| sort -k1,1 -k3,3 -k4,4 -k6,6n \
|
|
| awk 'BEGIN{print "StateGroup Protocol LocalAddr LocalIndex LocalPort PeerAddr PeerIndex PeerPort Process PID Cgroup"}1' \
|
|
| column -t \
|
|
| $_fzfCmd --multi --reverse --ansi --keep-right --tabstop 2 --header-lines 1 --prompt "List of LISTENING tcp/udp sockets > " --bind ctrl-a:select-all,ctrl-d:deselect-all,ctrl-t:toggle-all
|
|
}
|
|
|
|
# ==============================
|
|
# New commands or external programs
|
|
# ==============================
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# set shell working directory after leaving Vifm
|
|
if command -v vifmrun 1> /dev/null; then
|
|
vfcd() {
|
|
local dst="$(command vifmrun --choose-dir - "$@")"
|
|
if [ -z "$dst" ]; then
|
|
echo 'Directory picking cancelled/failed'
|
|
return 1
|
|
fi
|
|
cd "$dst"
|
|
}
|
|
fi
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# simple archive extraction of all kinds, get dep with "sudo apt install tar bzip2 unrar gzip unzip 7zip xz-utils innoextract cabextract"
|
|
extract() {
|
|
|
|
Help() {
|
|
cat <<- HEREDOC
|
|
|
|
Archive extraction simplified.
|
|
Syntax: extract [-h] <path/file_name>.<zip|rar|bz2|gz|tar|tbz2|tgz|Z|7z|xz|ex|tar.bz2|tar.gz|tar.xz>
|
|
extract <path/file_name_1.ext> [path/file_name_2.ext] [path/file_name_3.ext]
|
|
options:
|
|
-h Print this Help.
|
|
|
|
HEREDOC
|
|
}
|
|
while getopts ":h" option; do
|
|
case $option in
|
|
h) Help; return 0 ;;
|
|
\?) echo -e "Unknown option: -$OPTARG \n" >&2; Help; return 1;;
|
|
: ) echo -e "Missing argument for -$OPTARG \n" >&2; Help; return 1;;
|
|
* ) echo -e "Unimplemented option: -$option \n" >&2; Help; return 1;;
|
|
esac
|
|
done
|
|
|
|
array=( tar unlzma bunzip2 unrar gunzip unzip uncompress 7z unxz innoextract cabextract )
|
|
for cmd in "${array[@]}"; do
|
|
if [[ -z $(command -v "$cmd") ]]; then
|
|
echo "Requirements: at least $cmd could not be found:"
|
|
echo "sudo apt install tar bzip2 unrar gzip unzip 7zip xz-utils innoextract cabextract"
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
for n in "$@"
|
|
do
|
|
if [[ -f "$n" ]] ; then
|
|
case "${n%,}" in
|
|
*.tar.bz2|*.tar.gz|*.tar.xz|*.tbz2|*.tgz|*.txz|*.tar)
|
|
tar xvf "$n" ;;
|
|
*.lzma) unlzma ./"$n" ;;
|
|
*.bz2) bunzip2 ./"$n" ;;
|
|
*.rar) unrar x -ad ./"$n" ;;
|
|
*.gz) gunzip ./"$n" ;;
|
|
*.zip) unzip ./"$n" ;;
|
|
*.z) uncompress ./"$n" ;;
|
|
*.7z|*.arj|*.cab|*.chm|*.deb|*.dmg|*.iso|*.lzh|*.msi|*.rpm|*.udf|*.wim|*.xar)
|
|
7z x ./"$n" ;;
|
|
*.xz) unxz ./"$n" ;;
|
|
*gog*.exe|*gog*.sh)
|
|
innoextract -es -c1 -p1 ./"$n" ;;
|
|
*.exe) cabextract ./"$n" ;;
|
|
*) echo "extract: '$n' - unknown archive method"; return 1;;
|
|
esac
|
|
else
|
|
echo "'$n' - file does not exist"
|
|
return 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# Command execution notifier
|
|
boop() {
|
|
|
|
Help() {
|
|
cat <<- HEREDOC
|
|
|
|
Command execution notifier.
|
|
- In front of a command: notification + sound + NTFY (env: NTFYBOOPSURL, NTFYBOOPSTOKEN)
|
|
(It send the command name and 1st arg, exec time and exit code)
|
|
- At the end of a chain: notification + sound
|
|
|
|
Syntax: Pre command: boop [-h] [sudo] <some command> | boop <some command>; boop <some command>
|
|
Post command: <some command>; boop
|
|
options:
|
|
-h Print this Help.
|
|
|
|
HEREDOC
|
|
}
|
|
while getopts ":h" option; do
|
|
case $option in
|
|
h) Help; return 0 ;;
|
|
\?) echo -e "Unknown option: -$OPTARG \n" >&2; Help; return 1;;
|
|
: ) echo -e "Missing argument for -$OPTARG \n" >&2; Help; return 1;;
|
|
* ) echo -e "Unimplemented option: -$option \n" >&2; Help; return 1;;
|
|
esac
|
|
done
|
|
|
|
local STATUS="$?"
|
|
local ARRAY1=( /usr/bin/time play dunstify )
|
|
local ARRAY2=( /usr/bin/time curl )
|
|
for cmd in "${ARRAY2[@]}"; do
|
|
if [[ -z $(command -v "$cmd") ]]; then
|
|
echo "boop function requirements: command $cmd could not be found"
|
|
return 1
|
|
fi
|
|
done
|
|
if [[ -z "$1" ]]; then
|
|
for cmd in "${ARRAY1[@]}"; do
|
|
if [[ -z $(command -v "$cmd") ]]; then
|
|
echo "boop function requirements: command $cmd could not be found"
|
|
return "$STATUS"
|
|
fi
|
|
done
|
|
if [[ "$STATUS" == '0' ]]; then
|
|
dunstify -a NTFY -u normal -i dialog-information "Commande terminée avec SUCCÉE ✅ !"
|
|
play -q -n synth pl G2 pl B2 pl D3 pl B3 pl D4 pl D4 delay 0 .05 .1 .15 .2 .25 remix - fade 0 2 .1 norm -1
|
|
else
|
|
dunstify -a NTFY -u critical -i dialog-error "Commande terminée avec une ERREUR ⚠️ !" "Exit code : $STATUS"
|
|
play -q -n synth 3 sin 960 synth 3 sin fmod 1920 fade l 0 3 2.8 trim 0 1 repeat 2 norm -1
|
|
fi
|
|
return "$STATUS"
|
|
else
|
|
local FILE=$(mktemp --suffix ".time")
|
|
boop2ntfy() {
|
|
local TIME=$(awk 'NR==1{print $1}' "$FILE")
|
|
local STATUS=$(awk 'NR==1{print $2}' "$FILE")
|
|
if [[ -z $(awk 'NR==1{print $4}' "$FILE") ]]; then
|
|
local CMDBEGIN=$(awk 'NR==1{print $3}' "$FILE")
|
|
else
|
|
local CMDBEGIN="$(awk 'NR==1{print $3}' "$FILE") $(awk 'NR==1{print $4}' "$FILE")"
|
|
fi
|
|
local HOSTNAME=$(hostname)
|
|
local URL="$NTFYBOOPSURL"
|
|
local TOKEN="$NTFYBOOPSTOKEN"
|
|
if [[ "$STATUS" == '0' ]]; then
|
|
if command -v dunstify 1> /dev/null; then
|
|
dunstify -a NTFY -u normal -i dialog-information "Commande terminée avec SUCCÉE ✅ !" "Durée : $TIME - Commande : $CMDBEGIN"
|
|
fi
|
|
if command -v play 1> /dev/null; then
|
|
play -q -n synth pl G2 pl B2 pl D3 pl B3 pl D4 pl D4 delay 0 .05 .1 .15 .2 .25 remix - fade 0 2 .1 norm -1
|
|
fi
|
|
curl --max-time 25 -s -S -H "Authorization: Bearer ${TOKEN}" -H "X-Title: Hôte : $HOSTNAME" -H tag:tada -d "La commande \"$CMDBEGIN\" s'est terminée avec Succès ! (Durée : $TIME)" "$URL" &> /dev/null
|
|
else
|
|
if command -v dunstify 1> /dev/null; then
|
|
dunstify -a NTFY -u critical -i dialog-error "Commande terminée avec une ERREUR ⚠️ !" "Durée : $TIME - Exit code : $STATUS - Commande : $CMDBEGIN"
|
|
fi
|
|
if command -v play 1> /dev/null; then
|
|
play -q -n synth 3 sin 960 synth 3 sin fmod 1920 fade l 0 3 2.8 trim 0 1 repeat 2 norm -1
|
|
fi
|
|
curl --max-time 25 -s -S -H "Authorization: Bearer ${TOKEN}" -H "X-Title: Hôte : $HOSTNAME" -H "X-Priority: 4" -H tag:warning -d "La commande \"$CMDBEGIN\" s'est interrompue avec le code d'Erreur $STATUS ! (Durée : $TIME)" "$URL" &> /dev/null
|
|
fi
|
|
}
|
|
/usr/bin/time -q -f "%E %x %C" -o "$FILE" "$@"; boop2ntfy
|
|
local EXIT=$(awk 'NR==1{print $2}' "$FILE")
|
|
rm -f "$FILE"
|
|
return "$EXIT"
|
|
fi
|
|
}
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# download a file from Google Drive with continuation : gdrive-dl ID FILENAME
|
|
gdrivedl() {
|
|
|
|
Help() {
|
|
cat <<- HEREDOC
|
|
|
|
Download a file from Google Drive with continuation.
|
|
Syntax: gdrive-dl [-h] <sharing ID from gdrive uri> <output file name>
|
|
options:
|
|
-h Print this Help.
|
|
|
|
HEREDOC
|
|
}
|
|
while getopts ":h" option; do
|
|
case $option in
|
|
h) Help; return 0 ;;
|
|
\?) echo -e "Unknown option: -$OPTARG \n" >&2; Help; return 1;;
|
|
: ) echo -e "Missing argument for -$OPTARG \n" >&2; Help; return 1;;
|
|
* ) echo -e "Unimplemented option: -$option \n" >&2; Help; return 1;;
|
|
esac
|
|
done
|
|
|
|
local _ID=$1
|
|
local _FILENAME=$2
|
|
wget --prefer-family=IPv4 --force-directories --no-check-certificate --no-hsts --continue --load-cookies "/tmp/gdrive-cookies-${_ID}.txt" \
|
|
"https://docs.google.com/uc?export=download&confirm=$(wget --quiet --save-cookies /tmp/gdrive-cookies-${_ID}.txt \
|
|
--keep-session-cookies --no-check-certificate 'https://docs.google.com/uc?export=download&id=${_ID}' -O- | \
|
|
sed -rn 's/.*confirm=([0-9A-Za-z_]+).*/\1\n/p')&id=${_ID}" -O "${XDG_DOWNLOAD_DIR}/$_FILENAME" \
|
|
&& rm -rf "/tmp/gdrive-cookies-${_ID}.txt"
|
|
}
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# mans - print brief help about a single option or command
|
|
mans() {
|
|
Help() {
|
|
cat <<- HEREDOC 1>&2
|
|
|
|
Mans print brief help about a single option or command
|
|
|
|
Usage: mans <command> [<option|section>]
|
|
Example:
|
|
mans bash getopts Documentation for bash getopts
|
|
mans ssh -v Documentation for ssh -v flag
|
|
mans select SYNOPSIS for select(2)
|
|
mans 'open(2)' SYNOPSIS for open(2)
|
|
|
|
HEREDOC
|
|
}
|
|
|
|
if test $# -lt 1; then
|
|
Help
|
|
return 0
|
|
fi
|
|
|
|
manpage="$1"
|
|
# show the SYNOPSIS section if no section or option was given
|
|
option="${2:-SYNOPSIS}"
|
|
|
|
# handle manpage(number)
|
|
case $manpage in *\(*\))
|
|
page=${manpage%\(*\)}
|
|
section=${manpage#"$page"}
|
|
section=${section#\(}
|
|
section=${section%\)}
|
|
manpage="$page"
|
|
;;
|
|
esac
|
|
|
|
man ${section:+-s $section} "$manpage" | perl -n -e \
|
|
'BEGIN {
|
|
$option = "'"$option"'";
|
|
$inside_option = 0;
|
|
}
|
|
if (!$inside_option) {
|
|
if (/^(\s*)\Q$option\E\b/p) {
|
|
# start of this option
|
|
$option_indentation = $1;
|
|
$inside_option = 1;
|
|
$saw_blank_line = 0;
|
|
print;
|
|
}
|
|
} else {
|
|
if (/^$/) {
|
|
$saw_blank_line = 1;
|
|
print;
|
|
} elsif (/^\Q$option_indentation\E\S/ and $saw_blank_line) {
|
|
# item at same indentation => start of next option
|
|
$inside_option = 0;
|
|
} elsif (/^\S/) {
|
|
# new heading => start of next section
|
|
$inside_option = 0;
|
|
} else {
|
|
print;
|
|
}
|
|
}' | { if command -v hl 1> /dev/null; then hlauto --man; else cat -; fi }
|
|
}
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
# br - This function starts broot and executes the command
|
|
if command -v br 1> /dev/null; then
|
|
br() {
|
|
local cmd cmd_file code
|
|
cmd_file=$(mktemp)
|
|
if broot --outcmd "$cmd_file" "$@"; then
|
|
cmd=$(<"$cmd_file")
|
|
command rm -f "$cmd_file"
|
|
eval "$cmd"
|
|
else
|
|
code=$?
|
|
command rm -f "$cmd_file"
|
|
return "$code"
|
|
fi
|
|
}
|
|
fi
|