#!/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] [] 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] [] Output: ServiceName UID STATE DESCRIPTION options: -h Print this Help. -x Copy the list to Clipboard with xclip. -p Disable the pager feature. [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] [] 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] "" [] 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 " 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] . extract [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] | boop ; boop Post 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] 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 if [[ -z "$XDG_DOWNLOAD_DIR" ]]; then mkdir $HOME/Downloads local _XDG_DOWNLOAD_DIR="$HOME/Downloads" else local _XDG_DOWNLOAD_DIR="$XDG_DOWNLOAD_DIR" fi 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 [] 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