From 2ece711e1af1e4f4edf05048e20abfe7aae3d497 Mon Sep 17 00:00:00 2001 From: fatalerrors Date: Fri, 6 Mar 2026 17:46:26 +0100 Subject: [PATCH] huge longrun improvements --- profile.d/compress.sh | 223 ++++++++------ profile.d/debug.sh | 77 +++-- profile.d/disp.sh | 18 +- profile.d/filefct.sh | 652 ++++++++++++++++++++++++++++++++--------- profile.d/fun.sh | 66 ++++- profile.d/help.sh | 61 ++-- profile.d/info.sh | 13 +- profile.d/lang.sh | 41 ++- profile.d/net.sh | 11 +- profile.d/packages.sh | 68 +++-- profile.d/processes.sh | 91 +++++- profile.d/prompt.sh | 21 +- profile.d/pwd.sh | 163 ++++++----- profile.d/rain.sh | 57 ++-- profile.d/ssh.sh | 79 +++-- profile.d/updates.sh | 71 ++++- version | 2 +- 17 files changed, 1233 insertions(+), 481 deletions(-) diff --git a/profile.d/compress.sh b/profile.d/compress.sh index 8cfd137..56e5e15 100644 --- a/profile.d/compress.sh +++ b/profile.d/compress.sh @@ -35,8 +35,13 @@ # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ -# Smartly uncompress archives (zip only for now) -# ------------------------------------------------------------------------------ +# Smartly uncompress archives +# Usage: utaz [option] [directorie(s)|file(s)] +# Options: +# -h, --help Display that help screen +# -d, --delete If decompression succeeded, delete the source file +# -c, --create-dir Always create a host directory +# -n, --no-dir Never create a host directory utaz() { _ununzip() @@ -136,53 +141,73 @@ utaz() rpm2cpio "$1" | (cd "$2/" && cpio -idmv) >/dev/null 2>&1 } - for opt in $@; do - case ${opt} in - "-h" | "--help") - echo "utaz: uncompress all the given files and/or the ones found in the given" - echo " directories creating an host directory where needed." - echo - echo "Usage: utaz [option] [directorie(s)|file(s)]" - echo - echo "Options:" - echo " -h, --help Display that help screen" - echo " -d, --delete If decompression succeeded, delete the source file" - echo " -c, --create-dir Always create a host directory" - echo " -n, --no-dir Never create a host directory" - echo + local PARSED=$(getopt -o hdcn --long help,delete,create-dir,no-dir -n 'utaz' -- "$@") + + if [ $? -ne 0 ]; then + disp E "Invalid options, use \"utaz --help\" to display usage." + return 1 + fi + eval set -- "$PARSED" + while true; do + case "$1" in + -h|--help) + printf "utaz: uncompress all the given files and/or the ones found in the given\n" + printf " directories creating an host directory where needed.\n\n" + printf "Usage: utaz [option] [directorie(s)|file(s)]\n\n" + printf "Options:\n" + printf "\t-h, --help\t\tDisplay that help screen\n" + printf "\t-d, --delete\t\tIf decompression succeeded, delete the source file\n" + printf "\t-c, --create-dir\tAlways create a host directory\n" + printf "\t-n, --no-dir\t\tNever create a host directory\n\n" + printf "Supported archive format:\n" + printf "\t- zip\n" + printf "\t- tar.gz, .tgz\n" + printf "\t- tar.bz2, .tbz2\n" + printf "\t- tar.xz, .txz\n" + printf "\t- tar.lz, .tlz\n" + printf "\t- rar\n" + printf "\t- arj\n" + printf "\t- lha, lzh\n" + printf "\t- ace\n" + printf "\t- 7z, p7z\n" + printf "\t- zst\n" + printf "\t- cpio\n" + printf "\t- cab\n" + printf "\t- deb\n" + printf "\t- rpm\n" return 0 ;; - - "-d" | "--delete") + -d|--delete) local willrm=1 + shift ;; - - "-c" | "--create-dir") + -c|--create-dir) local createdir=1 + shift ;; - - "-n" | "--no-dir") + -n|--no-dir) local nodir=1 + shift ;; - - "-"*) - disp E "Invalid option, use \"utaz --help\" to display options list" - echo - return 1 + --) + shift + break ;; - *) - # The ${opt%/} writing is to remove trailing / if any - local LIST="${LIST} ${opt%/}" + disp E "Invalid option, use \"utaz --help\" to display options list" + return 1 ;; esac done + # The remaining arguments after -- are the files/directories to process, + # "." is used if none is given + local FILES=("$@") + [[ ${#FILES[@]} -eq 0 ]] && FILES=(".") [[ -n ${createdir} && -n ${nodir} ]] && \ disp E "The --create-dir and --no-dir options are mutually exclusive." - [[ -z ${LIST} ]] && local LIST="." - for zitem in ${LIST}; do + for zitem in "${FILES[@]}"; do for f in "${zitem}"/*; do local dir="${f%.*}" local extractor="" @@ -193,13 +218,13 @@ utaz() *.tar.gz|*.tgz) extractor="_ungzip" ;; - *.tar.bz2) + *.tar.bz2|*.tbz2) extractor="_unbzip2" ;; - *.tar.xz) + *.tar.xz|*.txz) extractor="_unxz" ;; - *.tar.lz) + *.tar.lz|*.tlz) extractor="_unlzop" ;; *.tar) @@ -217,7 +242,7 @@ utaz() *.ace) extractor="_ununace" ;; - *.7z) + *.7z|*.p7z) extractor="_un7z" ;; *.zst) @@ -277,10 +302,14 @@ utaz() rm -f "${f}" && disp I "File ${zitem}/${f} deleted." ;; 1) - disp W "Compression program returned a warning: deletion canceled." + if [[ -n ${willrm} ]]; then + disp W "Compression program returned a warning: deletion canceled." + else + disp W "Compression program returned a warning." + fi ;; *) - disp E "The zip file seems corrupted, failed." + disp E "The compressed file ${f} seems corrupted, failed." rm -rf "${dir}" >/dev/null 2>&1 continue ;; @@ -310,10 +339,21 @@ utaz() done } export -f utaz +# ------------------------------------------------------------------------------ + # ------------------------------------------------------------------------------ # Compress directories or files into one or more archive -# ------------------------------------------------------------------------------ +# Usage: taz [option] [--parallel=] [--format=] [directory1 ... directoryN] +# Options: +# -h, --help Display that help screen +# -d, --delete Delete source file or directory after success +# -f, --format Chose archive format in the given list. If several format are +# given, the smalest is kept +# -p, --parallel Number of threads to use (if allowed by underlying utility) +# -v, --verbose Display progress where possible +# -q, --quiet Display less messages (only errors and warnings) +# -1, .., -9 Compression level to use [1=fast/biggest, 9=slow/smallest] taz() { _doxz() @@ -421,78 +461,92 @@ taz() return $? } - for opt in $@; do - case $opt in - "-h" | "--help") - echo "taz: archive all files of a directory." - echo - echo "Usage: taz [option] [--parallel=] [--format=] [directory1 ... directoryN]" - echo - echo "Options:" - echo " -h, --help Display that help screen" - echo " -d, --delete Delete source file or directory after success" - echo " -f, --format Chose archive format in the given list. If several format are" - echo " given, the smalest is kept" - echo " -p, --parallel Number of threads to use (if allowed by underlying utility)" - echo " -v, --verbose Display progress where possible" - echo " -q, --quiet Display less messages (only errors and warnings)" - echo " -1, .., -9 Compression level to use [1=fast/biggest, 9=slow/smallest]" - echo - echo "Supported archive format:" - echo " Param.| programs | Algo. | Description" - echo " ------+---------------+-------+----------------------------------------" - echo " lz | plzip, lzip | lzma | Safe efficient default format" - echo " xz | xz | lzma2 | Unsafe, not for long term" - echo " bz2 | pbzip2, bzip2 | bzip2 | Historical but less efficient than lz" - echo " gz | pigz, gzip | lz77 | Historical, safe, fast" - echo " lzo | lzop | lzo | Very fast but no multithread" - echo " tar | tar | tar | No compression" - echo + local PARSED + PARSED=$(getopt -o hdf:p:vq123456789 --long help,delete,format:,parallel:,verbose,quiet --name "taz" -- "$@") + if [ $? -ne 0 ]; then + disp E "Invalid options, use \"taz --help\" to display usage." + return 1 + fi + eval set -- "$PARSED" + while true; do + case "$1" in + -h|--help) + printf "taz: archive all files of a directory.\n\n" + printf "Usage: taz [option] [--parallel=] [--format=] [directory1 ... directoryN]\n\n" + printf "Options:\n" + printf "\t-h, --help\tDisplay that help screen\n" + printf "\t-d, --delete\tDelete source file or directory after success\n" + printf "\t-f, --format\tChose archive format in the given list. If several format are" + printf "\t\t\tgiven, the smalest is kept\n" + printf "\t-p, --parallel\tNumber of threads to use (if allowed by underlying utility)\n" + printf "\t-v, --verbose\tDisplay progress where possible\n" + printf "\t-q, --quiet\tDisplay less messages (only errors and warnings)\n" + printf "\t-1, .., -9\tCompression level to use [1=fast/biggest, 9=slow/smallest]\n\n" + printf "Supported archive format:\n" + printf "\tParam.| programs | Algo. | Description\n" + printf "\t------+---------------+-------+----------------------------------------\n" + printf "\t lz | plzip, lzip | lzma | Safe efficient default format\n" + printf "\t xz | xz | lzma2 | Unsafe, not for long term\n" + printf "\t bz2 | pbzip2, bzip2 | bzip2 | Historical but less efficient than lz\n" + printf "\t gz | pigz, gzip | lz77 | Historical, safe, fast\n" + printf "\t lzo | lzop | lzo | Very fast but no multithread\n" + printf "\t tar | tar | tar | No compression\n" + printf "\n" return 0 ;; - "-d" | "--delete") + -d|--delete) local willrm=1 + shift ;; - "-f"?* | "--format"?*) - local compform=$(echo "$opt" | cut -f 2- -d '=') + -f|--format) + local compform=$2 + shift 2 ;; - "-p"?* | "--parallel"?*) - local nproc=$(echo "$opt" | cut -f 2- -d '=') + -p|--parallel) + local nproc=$2 + shift 2 ;; - "-v" | "--verbose") + -v|--verbose) local verbose=1 + shift ;; - "-q" | "--quiet") + -q|--quiet) local quiet=1 + shift ;; - "-"*) - local complevel=$(echo $opt | sed 's/-//') - if ! [[ $complevel =~ ^[1-9]+$ ]]; then - disp E "Invalid option, use taz --help to display options list" - echo - return 1 - fi + -[1-9]) + compression="${1#-}" + shift + ;; + --) + shift + break ;; - *) - local LIST="$LIST ${opt%/}" + disp E "Invalid option, use \"taz --help\" to display options list" + return 1 ;; esac done + # The remaining arguments after -- are the files/directories to process, + # "." is used if none is given + local FILES=("$@") + [[ ${#FILES[@]} -eq 0 ]] && FILES=(".") + [[ ! $compform ]] && compform=lz # safe and efficient (unless data are already compressed) [[ ! $nproc ]] && nproc=1 [[ ! $complevel ]] && complevel=6 [[ $verbose -gt 1 && $quiet -gt 1 ]] && disp E "The --verbose and --quiet options can't be used together." - for item in $LIST; do + for item in "${FILES[@]}"; do local donetar=0 disp I "Processing $item..." @@ -537,6 +591,7 @@ taz() unset quiet } export -f taz - # ------------------------------------------------------------------------------ + + # EOF diff --git a/profile.d/debug.sh b/profile.d/debug.sh index a55b8f9..ee5ee0f 100644 --- a/profile.d/debug.sh +++ b/profile.d/debug.sh @@ -36,27 +36,22 @@ # ------------------------------------------------------------------------------ # Display a backtrace -# ------------------------------------------------------------------------------ +# Usage: backtrace function backtrace() { - echo "========= Call stack =========" - typeset -i i=0 - - local func= - for func in "${FUNCNAME[@]}"; do - if [[ $i -ne 0 ]]; then - printf '%15s() %s:%d\n' \ - "$func" "${BASH_SOURCE[$i]}" "${BASH_LINENO[(($i - 1))]}" - fi - let i++ || true + printf "========= Call stack =========\n" + local i=1 # We begin at 1 to ignore backtrace itself + while [[ $i -lt ${#FUNCNAME[@]} ]]; do + printf '%15s() %s:%d\n' \ + "${FUNCNAME[$i]}" "${BASH_SOURCE[$i]}" "${BASH_LINENO[$(( i-1 ))]}" + ((i++)) done unset func i - echo "==============================" + printf "==============================\n" } # ------------------------------------------------------------------------------ # Function to be trapped for errors investigation -# ------------------------------------------------------------------------------ function error() { local errcode=$? @@ -66,45 +61,63 @@ function error() # ------------------------------------------------------------------------------ # Activate or deactivate error trapping to display backtrace -# ------------------------------------------------------------------------------ +# Usage: settrace <--on|--off|--status> settrace() { local status="off" [[ $(trap -p ERR) ]] && status="on" #trap -p ERR - for opt in $@; do - case $opt in - "-h" | "--help") - echo "Try to activate backtrace display for script debugging." - echo - echo "Options:" - echo " --on Activate backtrace generation" - echo " --off Deactivate backtrace generation" - echo - echo "That function active a trap event on error. If the script you want to" - echo "debug overload the ERR bash trap, it will not work." - echo + + local PARSED + PARSED=$(getopt -oh --long help,on,off,status -- "$@") + if [[ $? -ne 0 ]]; then + disp E "Invalid options, use \"settrace --help\" to display usage." + return 1 + fi + eval set -- "$PARSED" + while true; do + case $1 in + -h|--help) + printf "Try to activate backtrace display for script debugging.\n\n" + printf "Options:\n" + printf "\t--on\t\tActivate backtrace generation\n" + printf "\t--off\t\tDeactivate backtrace generation\n\n" + printf "That function active a trap event on error. If the script you want to\n" + printf "debug overload the ERR bash trap, it will not work.\n" + return 0 ;; - "--on") - if [[ $status == "on" ]]; then + --on) + if [[ ${status} == "on" ]]; then disp W "ERR signal trap is already set, replacing previous trap!" fi trap "error" ERR + shift ;; - "--off") - if [[ $status != "on" ]]; then + --off) + if [[ ${status} != "on" ]]; then disp W "ERR signal trap is already unset!" fi trap - ERR + shift ;; - "--status") + --status) disp "ERR trap signal is ${status}." + shift ;; + --) + shift + break + ;; + *) + disp E "Invalid options, use \"settrace --help\" to display usage." + return 1 + ;; esac done unset status } export -f settrace - # ------------------------------------------------------------------------------ + + # EOF diff --git a/profile.d/disp.sh b/profile.d/disp.sh index 70b7124..230b232 100644 --- a/profile.d/disp.sh +++ b/profile.d/disp.sh @@ -36,11 +36,10 @@ # ------------------------------------------------------------------------------ # Color definitions -# ------------------------------------------------------------------------------ # Standard 16 colors display declaration -export DEFAULTFG="\e[0;39m" -export DEFAULTBG="\e[0;49m" -export DEFAULTCOL=${DEFAULTBG}${DEFAULTFG} +export DEFAULTFG='\e[0;39m' +export DEFAULTBG='\e[0;49m' +export DEFAULTCOL="${DEFAULTBG}${DEFAULTFG}" export RESETCOL=$'\e[0m' # Regular Colors @@ -112,10 +111,17 @@ export On_IBlue='\e[0;104m' export On_IPurple='\e[0;105m' export On_ICyan='\e[0;106m' export On_IWhite='\e[0;107m' +# ------------------------------------------------------------------------------ + # ------------------------------------------------------------------------------ # Display a message -# ------------------------------------------------------------------------------ +# Usage: disp +# Types: +# I : info (green) +# W : warning (yellow) +# E : error (red) +# D : debug (cyan) disp() { case $1 in @@ -149,4 +155,6 @@ disp() } export -f disp # ------------------------------------------------------------------------------ + + # EOF diff --git a/profile.d/filefct.sh b/profile.d/filefct.sh index 87df535..aa5c763 100644 --- a/profile.d/filefct.sh +++ b/profile.d/filefct.sh @@ -36,9 +36,17 @@ # ------------------------------------------------------------------------------ # expandlist : treat wildcards in a file/directory list -# ------------------------------------------------------------------------------ +# Usage: expandlist expandlist() { + if [[ "$1" == "-h" || "$1" == "--help" ]]; then + printf "expandlist: Wraps a list of items in double quotes.\n\n" + printf "Usage: expandlist \n\n" + printf "Options:\n" + printf "\t-h, --help\t\tDisplay this help screen\n" + return 0 + fi + local result="" for item in "$1"; do for content in "$item"; do @@ -47,62 +55,78 @@ expandlist() done echo $result } +export -f expandlist +# ------------------------------------------------------------------------------ + # ------------------------------------------------------------------------------ # Clean a directory or a tree from temporary or backup files -# ------------------------------------------------------------------------------ +# Usage: clean [options] [directory1] [...[directoryX]] +# Options: +# -h, --help: display help screen +# -r, --recurs: do a recursive cleaning +# -f, --force: do not ask for confirmation (use with care) +# -s, --shell: do nothing and display what will be executed clean() { - for opt in $@; do - case $opt in - "-r" | "--recurs") - local recursive=1 - ;; + local recursive=0 force=0 outshell=0 - "-h" | "--help") - echo "clean: erase backup files in the given directories." - echo - echo "Usage: clean [option] [directory1] [...[directoryX]]" - echo - echo "Options:" - echo " -h, --help Display that help screen" - echo " -r, --recurs Do a recursive cleaning" - echo " -f, --force Do not ask for confirmation (use with care)" - echo " -s, --shell Do nothing and display what will be executed" - echo - return 0 - ;; + # Define short and long options + local PARSED + PARSED=$(getopt -o hrsf --long help,recurs,shell,force -n 'clean' -- "$@") - "-s" | "--shell") - local outshell=1 - ;; + if [[ $? -ne 0 ]]; then + disp E "Invalid options, use \"clean --help\" to display usage." + return 1 + fi - "-f" | "--force") - local force=1 - ;; + eval set -- "$PARSED" - "-"*) - disp E "Invalid option, use \"clean --help\" to display usage." - echo - return 1 - ;; - - *) - local dirlist="$dirlist $opt" - ;; + while true; do + case "$1" in + -r|--recurs) + local recursive=1 + shift + ;; + -h|--help) + printf "clean: erase backup files in the given directories.\n\n" + printf "Usage: clean [option] [directory1] [...[directoryX]]\n" + printf "Options:\n" + printf "\t-h, --help\t\tDisplay that help screen\n" + printf "\t-r, --recurs\t\tDo a recursive cleaning\n" + printf "\t-f, --force\t\tDo not ask for confirmation (use with care)\n" + printf "\t-s, --shell\t\tDo nothing and display what will be executed\n" + printf "\n" + return 0 + ;; + -s|--shell) + local outshell=1 + shift + ;; + -f|--force) + local force=1 + shift + ;; + --) + shift + break + ;; + *) + disp E "Invalid parameter, use \"clean --help\" to display options list" + return 1 esac done - [[ ! $dirlist ]] && local dirlist=$(pwd) + # Handle remaining arguments as directories + local dirlist=("$@") + [[ ${#dirlist[@]} -eq 0 ]] && dirlist=(".") [[ ! $recursive ]] && local findopt="-maxdepth 1" [[ ! $force ]] && local rmopt="-i" unset recursive force for dir in $dirlist; do - local dellist=$(find "$dir" $findopt -type f -name "*~" -o -name "#*#" \ - -o -name "*.bak" -o -name ".~*#") - for f in $dellist; do + find "$dir" "${findopt[@]}" -type f \( -name "*~" -o -name "#*#" -o -name "*.bak" -o -name ".~*#" \) -print0 | while IFS= read -r -d '' f; do if [[ ! $outshell ]]; then rm $rmopt $f else @@ -113,72 +137,103 @@ clean() unset outshell dirlist dellist findopt rmopt } export -f clean +# ------------------------------------------------------------------------------ + # ------------------------------------------------------------------------------ # Create a directory then goes inside -# ------------------------------------------------------------------------------ +# Usage: mcd mcd() { + if [[ "$1" == "-h" || "$1" == "--help" ]]; then + printf "mcd: Create a directory and enter it.\n\n" + printf "Usage: mcd \n" + printf "Options:\n" + printf "\t-h, --help\t\tDisplay this help screen\n" + return 0 + fi + if [[ ! $# -eq 1 ]]; then - disp E "Create a directory then goes inside." - disp E "Usage: mcd " + disp E "Missing parameter. Use \"mcd --help\" to display usage." return 1 fi - mkdir -pv "$1" && cd "$1" || echo "Failed create or change directory." + mkdir -pv "$1" && cd "$1" || { + printf "Failed create and/or change directory.\n" + return 1 + } } export -f mcd +# ------------------------------------------------------------------------------ + # ------------------------------------------------------------------------------ # Rename all files in current directory to replace spaces with _ -# ------------------------------------------------------------------------------ +# Usage: rmspc [options] +# Options: +# -h, --help: display help screen +# -r, --recursive: treat subdirectories of the given directory +# -c, --subst-char: change the replacement character (default is underscore) +# -v, --verbose: display more details (recursive mode only) +# -s, --shell: do nothing and display commands that would be executed rmspc() { local lst="" - for opt in $@; do - case $opt in - "-h" | "--help") - echo "rmspc: remove spaces from all filenames in current directories" - echo - echo "Usage: rmspc [option]" - echo - echo "Options:" - echo " -h, --help Display that help screen" - echo " -r, --recursive Treat subdirectories of the given directory" - echo " -c, --subst-char Change the replacement character (default is underscore)" - echo " -v, --verbose Display more details (recursive mode only)" - echo " -s, --shell Do nothing and display commands that would be executed" - echo - echo "Note: if the --subst-char option is given without parameters, spaces will be" - echo " replaced with nothing (concatenation)." - echo - return 0 - ;; + local PARSED + PARSED=$(getopt -o hr:c::vs --long help,recursive,subst-char::,verbose,shell -n 'rmspc' -- "$@") + if [[ $? -ne 0 ]]; then + disp E "Invalid options, use \"rmspc --help\" to display usage." + return 1 + fi + eval set -- "$PARSED" - "-r" | "--recursive") - local recurs=1 - ;; - - "-c"?* | "--subst-char"?*) - if [[ $(echo $opt | grep "=") ]]; then - local substchar=$(echo "$opt" | cut -f 2- -d '=') - else - local substchar='none' - fi - ;; - - "-v" | "--verbose") - local verb=1 - ;; - - "-s" | "--shell") - local shell=1 - ;; - - *) - disp E "Invalid parameter, use \"rmspc --help\" to display options list" - echo - return 1 - ;; + while true; do + case "$1" in + -h|--help) + printf "rmspc: remove spaces from all filenames in current directories\n\n" + printf "Usage: rmspc [option]\n\n" + printf "Options:\n" + printf "\t-h, --help\t\tDisplay that help screen\n" + printf "\t-r, --recursive\t\tTreat subdirectories of the given directory\n" + printf "\t-c, --subst-char\tChange the replacement character (default is underscore)\n" + printf "\t-v, --verbose\t\tDisplay more details (recursive mode only)\n" + printf "\t-s, --shell\t\tDo nothing and display commands that would be executed\n\n" + printf "Note: if the --subst-char option is given without parameters, spaces will be\n" + printf " replaced with nothing (concatenation).\n" + return 0 + ;; + -r|--recursive) + local recurs=1 + shift + ;; + -c|--subst-char) + # Handle optional argument for short/long options + case "$2" in + "") + substchar="" + ;; + *) + substchar="$2" + ;; + esac + shift 2 + ;; + -v|--verbose) + local verb=1 + shift + ;; + -s|--shell) + local shell=1 + shift + ;; + --) + shift + break + ;; + *) + disp E "Invalid parameter, use \"rmspc --help\" to display options list" + echo + return 1 + ;; esac done @@ -210,38 +265,119 @@ rmspc() unset lst substchar verb shell newf command mvopt } export -f rmspc +# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # display stats about a file structure -# ------------------------------------------------------------------------------ +# Usage: file_stats [options] [path] +# Options: +# -H, --human Human readable sizes\n" +# -d, --details Display details (min/max/average/median) +# -m, --average Display only average size +# -M, --median Display only median size +# -c, --count Display only count of files +# -t, --total Display only total size +# -a, --all Display all stats in human readable format (shortcut for -H -d) +# -x, --ext [ext] Filter by extension (e.g. -x log for .log files) +# -X, --ext-list [list] Filter by multiple extensions (e.g. -X log,txt) +# --min [size] Minimum size (e.g., 10M) +# --max [size] Maximum size (e.g., 100M) file_stats() { - local human=0 details=0 only_avg=0 only_med=0 only_count=0 only_total=0 +local human=0 details=0 only_avg=0 only_med=0 only_count=0 only_total=0 local path="." show_all=1 ext_filter="" ext_list="" min_size="" max_size="" - local OPTIND opt - # Analyse options - while [[ "$1" =~ ^- ]]; do + local PARSED + # Short: H, d, m, M, c, t, a, x:, X: + # Long: human, details, average, median, count, total, all, ext:, ext-list:, min:, max:, help + PARSED=$(getopt -o HdmMctax:X:h --long human,details,average,median,count,total,all,ext:,ext-list:,min:,max:,help -n 'file_stats' -- "$@") + + if [[ $? -ne 0 ]]; then + disp E "Invalid options, use \"file_stats --help\" to display usage." + return 1 + fi + eval set -- "$PARSED" + + while true; do case "$1" in - -H) human=1 ;; - -d) details=1 ;; - -m) only_avg=1; show_all=0 ;; - -M) only_med=1; show_all=0 ;; - -c) only_count=1; show_all=0 ;; - -t) only_total=1; show_all=0 ;; - -a) human=1; details=1 ;; - -x) ext_filter="${2#.}"; shift ;; - -X) ext_list="${2}"; shift ;; - --min) min_size="$2"; shift ;; - --max) max_size="$2"; shift ;; - --) shift; break ;; - -*) echo "Usage: file_stats [-h] [-d] [-mMctaxX --min N --max N] [path]"; return 1 ;; + -h|--help) + printf "Usage: file_stats [options] [path]\n\n" + printf "Options:\n" + printf "\t-H, --human\t\tHuman readable sizes\n" + printf "\t-d, --details\t\tShow detailed histogram\n" + printf "\t-m, --average\t\tShow only average size\n" + printf "\t-M, --median\t\tShow only median size\n" + printf "\t-c, --count\t\tShow only file count\n" + printf "\t-t, --total\t\tShow only total size\n" + printf "\t-a, --all\t\tShow all (human + details)\n" + printf "\t-x, --ext [ext]\t\tFilter by extension\n" + printf "\t-X, --ext-list [list]\tFilter by comma-separated list\n" + printf "\t--min [size]\t\tMinimum size (e.g., 10M)\n" + printf "\t--max [size]\t\tMaximum size (e.g., 100M)\n" + return 0 ;; + -H|--human) + human=1 + shift + ;; + -d|--details) + details=1 + shift + ;; + -m|--average) + only_avg=1 + show_all=0 + shift + ;; + -M|--median) + only_med=1 + show_all=0 + shift + ;; + -c|--count) + only_count=1 + show_all=0 + shift + ;; + -t|--total) + only_total=1 + show_all=0 + shift + ;; + -a|--all) + human=1 + details=1 + shift + ;; + -x|--ext) + ext_filter="${2#.}" + shift 2 + ;; + -X|--ext-list) + ext_list="$2" + shift 2 + ;; + --min) + min_size="$2" + shift 2 + ;; + --max) + max_size="$2" + shift 2 + ;; + --) + shift + break + ;; + *) + disp E "Invalid option: $1" + return 1 + ;; esac shift done - [ -n "$1" ] && path="$1" + [[ -n "$1" ]] && path="$1" # Prepare find filters local find_cmd=(find "$path" -type f) @@ -271,12 +407,27 @@ file_stats() fi # Exécution - "${find_cmd[@]}" -printf "%s\n" 2>/dev/null | sort -n | awk -v human="$human" -v details="$details" -v only_avg="$only_avg" -v only_med="$only_med" -v only_count="$only_count" -v only_total="$only_total" -v show_all="$show_all" -v path="$path" ' + "${find_cmd[@]}" -printf "%s\n" 2>/dev/null | sort -n | \ + awk -v human="$human" -v details="$details" -v only_avg="$only_avg" \ + -v only_med="$only_med" -v only_count="$only_count" \ + -v only_total="$only_total" -v show_all="$show_all" -v path="$path" ' + # Convert function function human_readable(x) { split("B KiB MiB GiB TiB", units) - for (i=1; x>=1024 && i<5; i++) x /= 1024 + i = 1 + while (x >= 1024 && i < 5) { + x /= 1024 + i++ + } return sprintf("%.2f %s", x, units[i]) } + + # Display function + function out(label, val, is_size) { + if (human == 1 && is_size == 1) val = human_readable(val) + printf "%-20s : %s\n", label, val + } + { sizes[NR] = $1 total += $1 @@ -288,50 +439,51 @@ file_stats() bucket[b]++ } } + END { count = NR if (count == 0) { - print "Aucun fichier trouvé."; exit + print "No files found." + exit } - moyenne = total / count - if (count % 2 == 1) - mediane = sizes[(count + 1) / 2] - else - mediane = (sizes[count / 2] + sizes[count / 2 + 1]) / 2 + average = total / count + # Simple sort for median (awk is not very good at this, we use existing logic) + if (count % 2 == 1) median = sizes[(count + 1) / 2] + else median = (sizes[count / 2] + sizes[count / 2 + 1]) / 2 - function out(label, val) { - if (human) val = human_readable(val) - printf "%-20s : %s\n", label, val - } - - if (only_avg) out("Taille moyenne", moyenne) - else if (only_med) out("Taille médiane", mediane) - else if (only_count) printf "Nombre de fichiers : %d\n", count - else if (only_total) out("Taille totale", total) + if (only_avg) out("Average size", average, 1) + else if (only_med) out("Median size", median, 1) + else if (only_count) out("Number of files", count, 0) + else if (only_total) out("Total size", total, 1) else { if (show_all || human || details) { - printf "Statistiques sur \"%s\"\n", path + printf "Statistics for \"%s\"\n", path printf "-------------------------\n" } - out("Nombre de fichiers", count) - out("Taille totale", total) - out("Taille moyenne", moyenne) - out("Taille médiane", mediane) - out("Taille minimale", min) - out("Taille maximale", max) + out("Number of files", count, 0) + out("Total size", total, 1) + out("Average size", average, 1) + out("Median size", median, 1) + out("Minimum size", min, 1) + out("Maximum size", max, 1) } - if (details) { - print "\nHistogramme des tailles :" - for (i = 0; i in bucket; i++) { - low = 2^i - high = 2^(i+1) - if (i == 0) - label = sprintf("%4s – %4s", "0", "1K") - else - label = sprintf("%4s – %4s", human_readable(low), human_readable(high)) - printf "%-20s : %5d fichiers\n", label, bucket[i] + print "\nSize histogram:" + + # Use a separate array for the loop to avoid collision + for (b in bucket) { + # Pre-calculate label parts + # 1024^0 = 1 (B), 1024^1 = 1K, etc. + low = (b == 0) ? 0 : (1024^b) + high = 1024^(b+1) + + label = sprintf("%-9s – %-9s", + (b == 0) ? "0" : human_readable(low), + human_readable(high)) + + # We store buckets in an array, access them by index b + printf "%-25s : %6d fichiers\n", label, bucket[b] } } }' @@ -341,4 +493,222 @@ export -f file_stats # ------------------------------------------------------------------------------ +# Find the biggest files in a directory tree +# Usage: findbig [options] [directory] +# Options: +# -h : display help screen +# -d : display details (ls -l) for each file +# -x : do not cross filesystem boundaries +# -l : limit : number of files to return (default is 10) +findbig() +{ + local details=0 limit=10 no_change=0 one_fs=0 + + local PARSED + PARSED=$(getopt -o hd:l:x --long help,details,one-fs,limit: -n 'findbig' -- "$@") + if [[ $? -ne 0 ]]; then + disp E "Invalid options, use \"findbig --help\" to display usage." + return 1 + fi + eval set -- "$PARSED" + + while true; do + case "$1" in + -h|--help) + printf "findbig: Find the N biggest files in a directory tree.\n\n" + printf "Usage: findbig [options] [directory]\n\n" + printf "Options:\n" + printf "\t-h, --help\t\tDisplay this help screen\n" + printf "\t-d, --details\t\tShow detailed file info (ls -ld)\n" + printf "\t-l, --limit N\t\tNumber of files to return (default: 10)\n" + printf "\t-x, --one-fs\t\tDo not cross filesystem boundaries\n" + return 0 + ;; + -d|--details) + details=1 + shift + ;; + -n|--no-change) + no_change=1 + shift + ;; + -l|--limit) + limit="$2" + shift 2 + ;; + --) + shift + break + ;; + *) + disp E "Invalid option: $1" + return 1 + ;; + esac + done + + local dir="${1:-.}" + + # Prepare find arguments in an array for cleaner handling + local find_args=("-L" "$dir" "-type" "f") + (( one_fs )) && find_args+=("-xdev") + + # Logic: find files, print size and path, sort numeric reverse, take N + if (( details )); then + find "${find_args[@]}" -printf "%s %p\n" 2>/dev/null | sort -rn | head -n "$limit" | while read -r size path; do + ls -ld "$path" + done + else + find "${find_args[@]}" -printf "%s %p\n" 2>/dev/null | sort -rn | head -n "$limit" + fi +} +export -f findbig +# ------------------------------------------------------------------------------ + + +# ------------------------------------------------------------------------------ +# Find empty files in a directory tree +# Usage: findzero [options] [directory] +# Options: +# -h : display help screen +# -d : display details (ls -l) for each file +# -x : do not cross filesystem boundaries +# --delete : delete empty files and display their paths +findzero() { + local delete=0 details=0 one_fs=0 no_change=0 + + local PARSED + # o: options, long: long equivalents + PARSED=$(getopt -o hdx --long help,details,one-fs,delete -n 'findzero' -- "$@") + if [[ $? -ne 0 ]]; then + disp E "Invalid options, use \"findzero --help\" to display usage." + return 1 + fi + eval set -- "$PARSED" + + while true; do + case "$1" in + -h|--help) + printf "findzero: Find or delete empty files in a directory tree.\n\n" + printf "Usage: findzero [options] [directory]\n\n" + printf "Options:\n" + printf "\t-h, --help\t\tDisplay this help screen\n" + printf "\t-d, --details\t\tShow detailed file info (ls -ls)\n" + printf "\t-x, --one-fs\t\tDo not cross filesystem boundaries\n" + printf "\t--delete\t\tActually remove the empty files\n" + return 0 ;; + -d|--details) + details=1 + shift + ;; + -x|--one-fs) + one_fs=1 + shift + ;; + --delete) + delete=1 + shift + ;; + --) + shift + break + ;; + *) + disp E "Invalid option: $1" + return 1 + ;; + esac + done + + local dir="${1:-.}" + local find_args=("-L" "$dir" "-type" "f" "-empty") + + (( one_fs )) && find_args+=("-xdev") + + # Execution logic + if (( delete )); then + disp W "Deleting empty files in $dir..." + find "${find_args[@]}" -delete -print + elif (( details )); then + find "${find_args[@]}" -ls + else + find "${find_args[@]}" + fi +} +export -f findzero +# ------------------------------------------------------------------------------ + + +# ------------------------------------------------------------------------------ +# Find dead symbolic links in a directory tree +# Usage: finddead [options] [directory] +# Options: +# -h : display help screen +# -d : display details (ls -l) for each link +# -x : do not cross filesystem boundaries +# --delete : delete dead links and display their paths +finddead() { + local delete=0 details=0 one_fs=0 no_change=0 + + local PARSED + PARSED=$(getopt -o hdx --long help,details,one-fs,delete -n 'finddead' -- "$@") + if [[ $? -ne 0 ]]; then + disp E "Invalid options, use \"finddead --help\" to display usage." + return 1 + fi + eval set -- "$PARSED" + + while true; do + case "$1" in + -h|--help) + printf "finddead: Find or delete dead/broken symbolic links.\n\n" + printf "Usage: finddead [options] [directory]\n\n" + printf "Options:\n" + printf "\t-h, --help\t\tDisplay this help screen\n" + printf "\t-d, --details\t\tShow detailed symlink info (ls -ls)\n" + printf "\t-x, --one-fs\t\tDo not cross filesystem boundaries\n" + printf "\t--delete\t\tActually remove the dead links\n" + return 0 ;; + -d|--details) + details=1 + shift + ;; + -x|--one-fs) + one_fs=1 + shift + ;; + --delete) + delete=1 + shift + ;; + --) + shift + break + ;; + *) + disp E "Invalid option: $1" + return 1 + ;; + esac + done + + local dir="${1:-.}" + # -xtype l searches for links that do not point to an existing file + local find_args=("$dir" "-xtype" "l") + (( one_fs )) && find_args+=("-xdev") + + # Execution logic + if (( delete )); then + disp W "Deleting dead symlinks in $dir..." + find "${find_args[@]}" -delete -print + elif (( details )); then + find "${find_args[@]}" -ls + else + find "${find_args[@]}" + fi +} +export -f finddead +# ------------------------------------------------------------------------------ + + # EOF diff --git a/profile.d/fun.sh b/profile.d/fun.sh index b7f08a0..657f623 100644 --- a/profile.d/fun.sh +++ b/profile.d/fun.sh @@ -36,35 +36,73 @@ # ------------------------------------------------------------------------------ # Make non-IT peoples think you're busy doing something hard -# ------------------------------------------------------------------------------ +# Usage: busy [options] [pattern] +# Options: +# --delay= : add a delay between each line output (milliseconds) +# pattern : the string to search for in the hexdump output (default is "ca fe") busy() { - local pattern="ca fe" - for arg in "$@"; do - case "$arg" in - --delay=*) - delay_ms="${arg#*=}" - if ! [[ $delay_ms =~ ^[0-9]+$ ]]; then - disp E "Invalid delay value, must be an integer (milliseconds)." + local pattern="ca fe" delay_ms=0 + + local PARSED + # Short: h, p:, d: + # Long: help, pattern:, delay: + PARSED=$(getopt -o hp:d: --long help,pattern:,delay: -n 'busy' -- "$@") + if [[ $? -ne 0 ]]; then + disp E "Invalid options, use \"busy --help\" to display usage." + return 1 + fi + eval set -- "$PARSED" + + while true; do + case "$1" in + -h|--help) + printf "busy: Monitor /dev/urandom for a specific pattern.\n\n" + printf "Usage: busy [options] [pattern]\n\n" + printf "Options:\n" + printf "\t-h, --help\t\tDisplay this help screen\n" + printf "\t-p, --pattern PATTERN\tHex pattern to search (default: \"ca fe\")\n" + printf "\t-d, --delay MS\t\tDelay between matches in milliseconds\n" + return 0 + ;; + -p|--pattern) + pattern="$2" + shift 2 + ;; + -d|--delay) + delay_ms="$2" + if ! [[ "$delay_ms" =~ ^[0-9]+$ ]]; then + disp E "Invalid delay: must be an integer (milliseconds)." return 1 fi + shift 2 + ;; + --) + shift + break ;; *) - pattern="$arg" + disp E "Invalid option: $1" + return 1 ;; esac done + # If a pattern was provided as a positional argument (e.g., 'busy "ff 00"'), + # it is captured here. + [[ -n "$1" ]] && pattern="$1" + # Convert milliseconds to seconds for 'sleep' local delay_s=$(awk "BEGIN { printf \"%.3f\", $delay_ms / 1000 }") + # Monitor /dev/urandom cat /dev/urandom | hexdump -C | grep --line-buffered "$pattern" | \ while read -r line; do - echo $line - [[ $delay_ms -gt 0 ]] && sleep "$delay_s" - done - unset pattern + echo "$line" + [[ $delay_ms -gt 0 ]] && sleep "$delay_s" + done } - # ------------------------------------------------------------------------------ + + # EOF diff --git a/profile.d/help.sh b/profile.d/help.sh index 66a64b4..f2c744b 100644 --- a/profile.d/help.sh +++ b/profile.d/help.sh @@ -36,38 +36,43 @@ # ------------------------------------------------------------------------------ # Display list of commands and general informations -# ------------------------------------------------------------------------------ +# Usage: help help() { - cat < --help to obtain usage details. -EOF + printf "\nPlease use --help to obtain usage details.\n" } export -f help - # ------------------------------------------------------------------------------ + + # EOF diff --git a/profile.d/info.sh b/profile.d/info.sh index d97e566..d2f23a7 100644 --- a/profile.d/info.sh +++ b/profile.d/info.sh @@ -36,7 +36,7 @@ # ------------------------------------------------------------------------------ # Show profile version -# ------------------------------------------------------------------------------ +# Usage: ver ver() { [[ -z $PROFVERSION ]] && \ @@ -45,10 +45,12 @@ ver() disp "Profile version $PROFVERSION." } export -f ver +# ------------------------------------------------------------------------------ + # ------------------------------------------------------------------------------ # Display weather of the given city (or default one) -# ------------------------------------------------------------------------------ +# Usage: meteo [city1 city2 ...] meteo() { local encoded cities=("$@") @@ -61,10 +63,12 @@ meteo() done } export -f meteo +# ------------------------------------------------------------------------------ + # ------------------------------------------------------------------------------ # Display system general information -# ------------------------------------------------------------------------------ +# Usage: showinfo showinfo() { echo -e "\n" @@ -99,6 +103,7 @@ showinfo() fi } export -f showinfo - # ------------------------------------------------------------------------------ + + # EOF diff --git a/profile.d/lang.sh b/profile.d/lang.sh index 5391ee5..6278408 100644 --- a/profile.d/lang.sh +++ b/profile.d/lang.sh @@ -34,7 +34,8 @@ # * OF SUCH DAMAGE. # ------------------------------------------------------------------------------ -locale_check() { +locale_check() +{ locale -a | grep -qx "$1" || { disp W "Locale '$1' is not installed on this system." return 1 @@ -45,9 +46,34 @@ locale_check() { # ------------------------------------------------------------------------------ # Change locale to the given one in parameter -# ------------------------------------------------------------------------------ +# Usage: setlocale setlocale() { + local PARSED + PARSED=$(getopt -o h --long help -n 'setlocale' -- "$@") + if [[ $? -ne 0 ]]; then + disp E "Invalid options, use \"setlocale --help\" to display usage." + return 1 + fi + eval set -- "$PARSED" + + case "$1" in + -h|--help) + printf "setlocale: Configure system environment locale variables.\n\n" + printf "Usage: setlocale \n\n" + printf "Options:\n" + printf " -h, --help Display this help screen\n" + return 0 + ;; + --) + shift + break + ;; + *) + disp E "Invalid options, use \"setlocale --help\" to display usage." + return 1 + ;; + esac local loc=$1 [[ -z $loc ]] && disp E "No locale specified." && return 1 @@ -64,11 +90,12 @@ setlocale() disp I "Locale set to $loc." } export -f setlocale +# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # Special case : change locale to C standard -# ------------------------------------------------------------------------------ +# Usage: setc setc() { # Locale definitions @@ -76,27 +103,31 @@ setc() disp I "Locale changed to standard C (POSIX)." } export -f setc +# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # Change locale to French -# ------------------------------------------------------------------------------ +# Usage: setfr setfr() { # Set fr locale definitions setlocale "fr_FR.UTF-8" } export -f setfr +# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # Change locale to US (needed by Steam) -# ------------------------------------------------------------------------------ +# Usage: setus setus() { setlocale "en_US.UTF-8" } export -f setus +# ------------------------------------------------------------------------------ + # ------------------------------------------------------------------------------ # EOF diff --git a/profile.d/net.sh b/profile.d/net.sh index 2936b2a..76862b7 100644 --- a/profile.d/net.sh +++ b/profile.d/net.sh @@ -36,7 +36,7 @@ # ------------------------------------------------------------------------------ # Determine if parameter is a valid IPv4 address -# ------------------------------------------------------------------------------ +# Usage: isipv4 isipv4() { # Set up local variables @@ -63,10 +63,12 @@ isipv4() return 1 } export -f isipv4 +# ------------------------------------------------------------------------------ + # ------------------------------------------------------------------------------ # Determine if parameter is a valid IPv4 address -# ------------------------------------------------------------------------------ +# Usage: isipv6 isipv6() { local ip="$1" @@ -83,10 +85,12 @@ isipv6() return 1 } export -f isipv6 +# ------------------------------------------------------------------------------ + # ------------------------------------------------------------------------------ # Encode a string so it can be used as a URL parameter -# ------------------------------------------------------------------------------ +# Usage: urlencode urlencode() { local LANG=C local str="$*" @@ -101,6 +105,7 @@ urlencode() { done } export -f urlencode +# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ diff --git a/profile.d/packages.sh b/profile.d/packages.sh index f06fe50..8a13965 100644 --- a/profile.d/packages.sh +++ b/profile.d/packages.sh @@ -36,38 +36,53 @@ # ------------------------------------------------------------------------------ # Look for a package within installed one -# ------------------------------------------------------------------------------ +# Usage: dpkgs pkgs() { - local count=0 - for opt in $@; do - case $opt in - "-h" | "--help") - echo "dpkgs: look for an installed package by it's name." - echo - echo "Usage: dpkgs " - return 0 - ;; + local ignore_case=0 - "-"*) - disp E "Invalid option, use \"dpkgs --help\" to display usage." - echo - return 1 - ;; + local PARSED + PARSED=$(getopt -o hi --long help,ignore-case -n 'pkgs' -- "$@") + if [[ $? -ne 0 ]]; then + disp E "Invalid options, use \"pkgs --help\" to display usage." + return 1 + fi + eval set -- "$PARSED" - *) - local pkg=$1 && shift - count=$(($count + 1)) - [[ $count -gt 1 ]] && - disp E "Please specify a package name, without space, eventually partial." && + while true; do + case "$1" in + -h|--help) + printf "pkgs: Look for an installed package by its name.\n\n" + printf "Usage: pkgs [options] \n\n" + printf "Options:\n" + printf "\t-h, --help\tDisplay this help screen\n" + printf "\t-i, --ignore-case\tIgnore case distinctions\n" + return 0 + ;; + -i|--ignore-case) + ignore_case=1 + shift + ;; + --) + shift + break + ;; + *) + disp E "Invalid option: $1" return 1 - - ;; + ;; esac done - [[ $count -lt 1 ]] && - disp E "Please specify a package name, without space, eventually partial." && + + local pkg="$1" + [[ -z "$pkg" ]] && { + disp E "Please specify a package name, without space, eventually partial." return 1 + } + + # Build grep command + local grep_opt="" + (( ignore_case )) && grep_opt="-i" command -v dpkg >/dev/null 2>&1 && local cmd="dpkg -l" command -v rpm >/dev/null 2>&1 && local cmd="rpm -qa" @@ -75,9 +90,10 @@ pkgs() disp E "No usable package manager seems unavialable." return 2 fi - $cmd | grep $pkg + $cmd | grep $grep_opt $pkg } export -f pkgs - # ------------------------------------------------------------------------------ + + # EOF diff --git a/profile.d/processes.sh b/profile.d/processes.sh index df10e12..dc004c1 100644 --- a/profile.d/processes.sh +++ b/profile.d/processes.sh @@ -36,18 +36,38 @@ # ------------------------------------------------------------------------------ # Search processes matching the given string -# ------------------------------------------------------------------------------ +# Usage: ppg ppg() { + if [[ "$1" == "-h" || "$1" == "--help" ]]; then + printf "ppg: Search processes matching the given string.\n\n" + printf "Usage: ppg \n\n" + printf "Options:\n" + printf "\t-h, --help\t\tDisplay this help screen\n" + return 0 + fi + if [[ -z "$1" ]]; then + disp E "Usage: ppg " + return 1 + fi ps -edf | grep "$@" | grep -v "grep $@" } export -f ppg +# ------------------------------------------------------------------------------ + # ------------------------------------------------------------------------------ # List processes owned by a specific user -# ------------------------------------------------------------------------------ +# Usage: ppu ppu() { + if [[ "$1" == "-h" || "$1" == "--help" ]]; then + printf "ppu: List processes owned by a specific user.\n\n" + printf "Usage: ppu \n\n" + printf "Options:\n" + printf "\t-h, --help\t\tDisplay this help screen\n" + return 0 + fi if [[ -z "$1" ]]; then disp E "Usage: ppu " return 1 @@ -58,12 +78,21 @@ ppu() ps -u "$1" -o pid,user,%cpu,%mem,start,time,command } export -f ppu +# ------------------------------------------------------------------------------ + # ------------------------------------------------------------------------------ # List processes by exact command name (no path/parameters) -# ------------------------------------------------------------------------------ +# Usage: ppn ppn() { + if [[ "$1" == "-h" || "$1" == "--help" ]]; then + printf "ppn: List processes by exact command name (no path/parameters).\n\n" + printf "Usage: ppn \n\n" + printf "Options:\n" + printf "\t-h, --help\t\tDisplay this help screen\n" + return 0 + fi if [[ -z "$1" ]]; then disp E "Usage: ppn " return 1 @@ -75,12 +104,25 @@ ppn() ps -eo pid,comm | grep -w "$1" } export -f ppn +# ------------------------------------------------------------------------------ + # ------------------------------------------------------------------------------ # Get PID list of the given process name -# ------------------------------------------------------------------------------ +# Usage: ppid gpid() { + if [[ "$1" == "-h" || "$1" == "--help" ]]; then + printf "gpid: Get PID list of the given process name.\n\n" + printf "Usage: gpid \n\n" + printf "Options:\n" + printf "\t-h, --help\t\tDisplay this help screen\n" + return 0 + fi + if [[ -z "$1" ]]; then + disp E "Usage: gpid " + return 1 + fi [[ $UID -eq 0 ]] && local psopt="-A" [[ $# -eq 1 ]] && local single=1 for pid in $@; do @@ -94,34 +136,65 @@ gpid() [[ $result ]] || return 1 } export -f gpid +# ------------------------------------------------------------------------------ + # ------------------------------------------------------------------------------ # Kill all processes owned by the given users (kill user) -# ------------------------------------------------------------------------------ +# Usage: ku ku() { + if [[ "$1" == "-h" || "$1" == "--help" ]]; then + printf "ku: Kill all processes owned by the given users.\n\n" + printf "Usage: ku \n\n" + printf "Options:\n" + printf "\t-h, --help\t\tDisplay this help screen\n" + return 0 + fi + if [[ -z "$1" ]]; then + disp E "Usage: ku " + return 1 + fi for u in $@; do killall -u "$u" done } export -f ku +# ------------------------------------------------------------------------------ + # ------------------------------------------------------------------------------ # Kill all children of a process then the process (kill tree) -# ------------------------------------------------------------------------------ +# Usage: kt [kill_options] kt() { - [[ -z $1 ]] && echo -e "Usage:\n\tkt [kill_options]" + if [[ "$1" == "-h" || "$1" == "--help" ]]; then + printf "kt: Kill all children of a process then the process (kill tree).\n\n" + printf "Usage: kt [kill_options]\n\n" + printf "Options:\n" + printf "\t-h, --help\t\tDisplay this help screen\n" + return 0 + fi + if [[ -z "$1" ]]; then + disp E "Usage: ppg " + return 1 + fi local parent_pid="$1" shift + if [[ "$parent_pid" == "0" || "$parent_pid" == "1" ]]; then + disp E "Safety abort: Refusing to kill PID $parent_pid (system critical)." + return 1 + fi + children_pids=$(pgrep -P "$parent_pid") for pid in $children_pids; do - kt "$pid" "$@" + kt "$pid" "$@" || break done kill "$@" "$parent_pid" } - # ------------------------------------------------------------------------------ + + # EOF diff --git a/profile.d/prompt.sh b/profile.d/prompt.sh index 6f65498..8f37d03 100644 --- a/profile.d/prompt.sh +++ b/profile.d/prompt.sh @@ -35,17 +35,26 @@ # ------------------------------------------------------------------------------ # timer_* functions : internal timing function for prompt -# ------------------------------------------------------------------------------ +# Usage: timer_now +# This function returns the current time in nanoseconds since the epoch. It +# first tries to use the %N format specifier for nanoseconds, but if that is +# not supported (e.g., on older systems), it falls back to seconds. function timer_now { date +%s%N 2>/dev/null || date +%s } +# Usage: timer_start +# This function initializes the timer_start variable with the current time in +# nanoseconds. It is used to measure the elapsed time for the prompt. function timer_start { timer_start=${timer_start:-$(timer_now)} } +# Usage: timer_stop +# This function calculates the elapsed time since timer_start and formats it +# into a human-readable string with appropriate units (us, ms, s, m, h function timer_stop { local delta_us=$((($(timer_now) - $timer_start) / 1000)) @@ -74,8 +83,11 @@ function timer_stop } # ------------------------------------------------------------------------------ -# Function triguered internaly by bash : defining prompt -# ------------------------------------------------------------------------------ +# Function triggered internally by bash : defining prompt +# Usage: set_prompt +# This function is called by bash before displaying the prompt. It sets the +# PS1 variable to a custom prompt that includes the exit status of the last +# command, the elapsed time of the last command, and the current user and host. set_prompt() { local Last_Command=$? # Must come first! @@ -123,6 +135,7 @@ set_prompt() # the text color to the default. PS1+="$ICyan\\w \\\$$Default " } - # ------------------------------------------------------------------------------ + + # EOF diff --git a/profile.d/pwd.sh b/profile.d/pwd.sh index e2af369..7244371 100644 --- a/profile.d/pwd.sh +++ b/profile.d/pwd.sh @@ -36,9 +36,20 @@ # ------------------------------------------------------------------------------ # genpwd : generate a password with different criteria -# default 16 car with up and low car, symbol and number +# Usage: genpwd [options] [--extracars=] [--length=] [nb_passwd] +# Options: +# -h, --help Display that help screen +# -s, --nosymbols Exclude symbols +# -n, --nonumbers Exclude numbers +# -u, --noup Exclude uppercase letters +# -l, --nolow Exclude lowercase letters +# -e=, --extracars= +# Add the given caracters to the possible caracter list +# -L=, --length= +# Set length of the password (default is 16) +# -o=, --occurences= +# Set the maximum occurences of a same caracter (default is 2) # The function is very slow on Windows -# ------------------------------------------------------------------------------ genpwd() { local length=16 @@ -47,80 +58,81 @@ genpwd() local nbpwd=1 local extcar - for opt in $@; do - case $opt in - "-h" | "--help") - echo "genpwd: generate one or more secure random password." - echo - echo "Usage: genpwd [options] [--extracars=] [--length=] [nb_passwd]" - echo - echo "Options:" - echo " -h, --help Display that help screen" - echo " -s, --nosymbols Exclude symbols" - echo " -n, --nonumbers Exclude numbers" - echo " -u, --noup Exclude uppercase letters" - echo " -l, --nolow Exclude lowercase letters" - echo " -e=, --extracars=" - echo " Add the given caracters to the possible caracter list" - echo " -L=, --length=" - echo " Set length of the password (default is $length)" - echo " -o=, --occurences=" - echo " Set the maximum occurences of a same caracter (default is $occurs)" - echo - echo "If the --extracars parameter is given, at least one of the given caracter will" - echo "be used in the final password." - echo - echo "Please note that some caracters might be interpreted by Bash or Awk programs," - echo "and thus, cannot be used without provoquing errors. Those identified caracters" - echo "are :" - echo ' * ? \ $ { }' - echo - return 0 - ;; - "-s" | "--nosymbols") - symb=0 - ;; - "-n" | "--nonumbers") - numb=0 - ;; - "-u" | "--noup") - maj=0 - ;; - "-l" | "--nolow") - min=0 - ;; - "-e"?* | "--extracars"?*) - extcar=$(echo "$opt" | cut -f 2- -d '=') - ;; - "-L"?* | "--length"?*) - local length=$(echo "$opt" | cut -f 2- -d '=') - if ! [[ $length =~ ^[0-9]+$ ]]; then - disp E "The --length parameter requires a number." - return 1 - fi - ;; - "-o"?* | "--occurences"?*) - local occurs=$(echo "$opt" | cut -f 2- -d '=') - if ! [[ $occurs =~ ^[1-9]+$ ]]; then - disp E "The --occurs parameter requires a number from 1 to 9." - return 1 - fi - ;; - "-*") - disp E "Unknow parameter ${opt}." - return 1 - ;; - *) - if ! [[ $opt =~ ^[1-9]+$ ]]; then - disp E "Unknow parameter ${opt}." - return 1 - else - nbpwd=$opt - fi - ;; +local PARSED + PARSED=$(getopt -o hsnu l e:L:o: --long \ + help,nosymbols,nonumbers,noup,nolow,extracars:,length:,occurences: -n 'genpwd' -- "$@") + if [[ $? -ne 0 ]]; then return 1; fi + eval set -- "$PARSED" + + while true; do + case "$1" in + -h|--help) + printf "genpwd: Generate secure random password(s).\n\n" + printf "Usage: genpwd [options] [nb_passwd]\n\n" + printf "Options:\n" + printf "\t-h, --help\t\tDisplay this help screen\n" + printf "\t-s, --nosymbols\t\tExclude symbols\n" + printf "\t-n, --nonumbers\t\tExclude numbers\n" + printf "\t-u, --noup\t\tExclude uppercase letters\n" + printf "\t-l, --nolow\t\tExclude lowercase letters\n" + printf "\t-e, --extracars \tAdd characters to list\n" + printf "\t-L, --length \tSet password length (default: 16)\n" + printf "\t-o, --occurences \tMax occurences per character (default: 2)\n" + return 0 + ;; + -s|--nosymbols) + symb=0 + shift + ;; + -n|--nonumbers) + numb=0 + shift + ;; + -u|--noup) + maj=0 + shift + ;; + -l|--nolow) + min=0 + shift + ;; + -e|--extracars) + extcar="$2" + shift 2 + ;; + -L|--length) + length="$2" + if ! [[ $length =~ ^[0-9]+$ ]]; then + disp E "The --length parameter requires a number." + return 1 + fi + shift 2 + ;; + -o|--occurences) + occurs="$2" + if ! [[ $occurs =~ ^[1-9]+$ ]]; then + disp E "The --occurs parameter requires a number from 1 to 9." + return 1 + fi + shift 2 + ;; + --) + shift; break + ;; + *) + break + ;; esac done + if [[ -n "$1" ]]; then + nbpwd="$1" + if ! [[ $nbpwd =~ ^[0-9]+$ ]]; then + disp E "The number of password to generate must be a number." + return 1 + fi + fi + # Function selecting a random caracter from the list in parameter pickcar() { # When a character is picked we check if it's not appearing already twice @@ -136,7 +148,7 @@ genpwd() } disp I "Generating $nbpwd passwords, please wait..." - for n in $(seq 1 $nbpwd); do + for (( n=1; n<=nbpwd; n++ )); do { local carset='' # store final caracter set to use local picked='' # store already used caracter @@ -185,6 +197,7 @@ genpwd() done } export -f genpwd - # ------------------------------------------------------------------------------ + + # EOF diff --git a/profile.d/rain.sh b/profile.d/rain.sh index ca7a067..0f2e800 100644 --- a/profile.d/rain.sh +++ b/profile.d/rain.sh @@ -36,27 +36,36 @@ # ------------------------------------------------------------------------------ # Let the rain fall -# ------------------------------------------------------------------------------ +# Usage: rain [OPTIONS] +# Options: +# -s, --speed NUM Set the drop delay in seconds (default: 0.050). +# Lower values = faster rain. +# -c, --color COLOR Set the color theme (default: white). +# -h, --help Display this help message and exit. +# Available Colors: +# green : The classic Matrix digital rain +# blue : Deep ocean blue gradients +# red : Crimson/Blood rain +# yellow : Amber and gold tones +# cyan : Electric cyan/turquoise +# white : Greyscale and white (original style) rain() { show_usage() { - echo -e "Usage: rain [OPTIONS]" - echo -e "" - echo -e "Options:" - echo -e " -s, --speed NUM Set the drop delay in seconds (default: 0.050)." - echo -e " Lower values = faster rain." - echo -e " -c, --color COLOR Set the color theme (default: white)." - echo -e " -h, --help Display this help message and exit." - echo -e "" - echo -e "Available Colors:" - echo -e " \e[32mgreen\e[0m : The classic Matrix digital rain" - echo -e " \e[34mblue\e[0m : Deep ocean blue gradients" - echo -e " \e[31mred\e[0m : Crimson/Blood rain" - echo -e " \e[33myellow\e[0m : Amber and gold tones" - echo -e " \e[36mcyan\e[0m : Electric cyan/turquoise" - echo -e " white : Greyscale and white (original style)" - echo -e "" - echo -e "Example: rain --color green --speed 0.03" + printf "Usage: rain [OPTIONS]\n" + printf "Options:\n" + printf "\t-s, --speed NUM Set the drop delay in seconds (default: 0.050).\n" + printf "\t Lower values = faster rain.\n" + printf "\t-c, --color COLOR Set the color theme (default: white).\n" + printf "\t-h, --help Display this help message and exit.\n\n" + printf "Available Colors:\n" + printf "\t\e[32mgreen\e[0m\t: The classic Matrix digital rain\n" + printf "\t\e[34mblue\e[0m\t: Deep ocean blue gradients\n" + printf "\t\e[31mred\e[0m\t: Crimson/Blood rain\n" + printf "\t\e[33myellow\e[0m\t: Amber and gold tones\n" + printf "\t\e[36mcyan\e[0m\t: Electric cyan/turquoise\n" + printf "\twhite\t: Greyscale and white (original style)\n\n" + printf "Example: rain --color green --speed 0.03\n" } local step_duration=0.050 @@ -69,7 +78,7 @@ rain() if [[ -n "$2" && ! "$2" =~ ^- ]]; then step_duration="$2"; shift else - echo -e "\e[31mError: --speed requires a numeric value.\e[0m" + disp E "--speed requires a numeric value." show_usage && return 1 fi ;; @@ -77,7 +86,7 @@ rain() if [[ -n "$2" && ! "$2" =~ ^- ]]; then base_color="$2"; shift else - echo -e "\e[31mError: --color requires a color name.\e[0m" + disp E "--color requires a color name." show_usage && return 1 fi ;; @@ -85,7 +94,7 @@ rain() show_usage && return 0 ;; *) - echo -e "\e[31mUnknown option: $1\e[0m" + disp E "Unknown option: $1" show_usage && return 1 ;; esac @@ -168,7 +177,7 @@ rain() drop_length=${rains[idx + 4]} for ((y = Y; y < Y + drop_length; y++)); do ((y < 1 || y > term_height)) && continue - echo -ne "\e[${y};${X}H${drop_color}${rain_drop}" + printf "\e[${y};${X}H${drop_color}${rain_drop}" done done } @@ -177,9 +186,9 @@ rain() trap sigwinch WINCH # No echo stdin and hide the cursor stty -echo - echo -ne "\e[?25l" + printf "\e[?25l" + printf "\e[2J" - echo -ne "\e[2J" local rains=() local num_rains=0 sigwinch diff --git a/profile.d/ssh.sh b/profile.d/ssh.sh index d9ae409..131c38b 100644 --- a/profile.d/ssh.sh +++ b/profile.d/ssh.sh @@ -36,17 +36,42 @@ # ------------------------------------------------------------------------------ # Remove host from know_host (name and IP) for the active user -# ------------------------------------------------------------------------------ +# Usage: rmhost [hostname2|ip2 [...]] rmhost() { - if [[ "$#" -lt 1 ]]; then - disp E "Incorrect number of parameters." - disp E "Usage: rmhost [hostname2|ip2 [...]]" + local PARSED + PARSED=$(getopt -o h --long help -n 'rmhost' -- "$@") + if [[ $? -ne 0 ]]; then return 1; fi + eval set -- "$PARSED" + + while true; do + case "$1" in + -h|--help) + printf "rmhost: Remove host/IP from ~/.ssh/known_hosts.\n\n" + printf "Usage: rmhost [hostname2|ip2 ...]\n\n" + printf "Options:\n" + printf " -h, --help Display this help screen\n" + return 0 + ;; + --) + shift + break + ;; + *) + disp E "Invalid options, use \"rmhost --help\" to display usage." + break + ;; + esac + done + + # Validation: Ensure at least one argument remains + if [[ $# -eq 0 ]]; then + disp E "Missing argument. Use 'rmhost --help' for usage." return 1 fi - while [[ $1 ]]; do - local hst=$1 && shift + for target in "$@"; do + local hst=$target isipv4 "$hst" >/dev/null local v4=$? isipv6 "$hst" >/dev/null @@ -81,20 +106,36 @@ rmhost() done } export -f rmhost +# ------------------------------------------------------------------------------ + # ------------------------------------------------------------------------------ # Login root via SSH on the given machine -# ------------------------------------------------------------------------------ +# Usage: ssr ssr() { - for opt in $@; do - case $opt in - "-h" | "--help") - echo "ssr: do a root user ssh login." - echo - echo "Usage: ssr " - return 0 - ;; + local PARSED + PARSED=$(getopt -o h --long help -n 'ssr' -- "$@") + if [[ $? -ne 0 ]]; then return 1; fi + eval set -- "$PARSED" + + while true; do + case "$1" in + -h|--help) + printf "ssr: SSH into a server as root.\n\n" + printf "Usage: ssr [ssh_options...]\n\n" + printf "Options:\n" + printf "\t-h, --help\t\tDisplay this help screen\n" + return 0 + ;; + --) + shift + break + ;; + *) + disp E "Invalid options, use \"ssr --help\" to display usage." + return 1 + ;; esac done @@ -102,15 +143,17 @@ ssr() disp E "ssh is not installed." return 127 } - [[ ! $1 ]] && - disp E "Please specify the server you want to log in." && + [[ ! $1 ]] && { + disp E "Please specify the server you want to log in." return 1 + } local srv=$1 && shift ssh -Y root@"$srv" "$@" } export -f ssr - # ------------------------------------------------------------------------------ + + # EOF diff --git a/profile.d/updates.sh b/profile.d/updates.sh index e33eece..3d52f8b 100644 --- a/profile.d/updates.sh +++ b/profile.d/updates.sh @@ -40,14 +40,40 @@ export ARCH_URL="$BASE_URL/archive/master.tar.gz" # ------------------------------------------------------------------------------ # Check for profile updates -# ------------------------------------------------------------------------------ +# Usage: check_updates [-q] +# If -q is specified, the function will operate in quiet mode (internal use only) check_updates() { - if [[ $1 == "-q" ]]; then - # Quiet mode is mostly used internally when profile_upgrade is called - quiet=1 + local quiet=0 + local PARSED=$(getopt -o hq --long help,quiet -n 'check_updates' -- "$@") + if [[ $? -ne 0 ]]; then + disp E "Invalid options, use \"check_updates --help\" to display usage." + return 1 fi - [[ -n $quiet ]] && disp I "Checking for updates..." + eval set -- "$PARSED" + + while true; do + case "$1" in + -h|--help) + printf "check_updates: Check for new versions.\n\n" + printf "Usage: check_updates\n" + return 0 + ;; + -q|--quiet) + quiet=1 + shift + ;; + --) + shift + break + ;; + *) + break + ;; + esac + done + + [[ $quiet != 1 ]] && disp I "Checking for updates..." local vfile="/tmp/version" wget "$UPDT_URL/version" -O $vfile >/dev/null 2>&1 || { disp E "Can't download version file, impossible to proceed!" @@ -58,10 +84,10 @@ check_updates() local lastver=$(cat $vfile) if [[ $lastver != $PROFVERSION ]]; then disp I "You have version $PROFVERSION installed. Version $lastver is available." - [[ $quiet ]] && disp I "You should upgrade to last version when possible." + [[ $quiet != 1 ]] && disp I "You should upgrade to last version when possible." result=1 else - [[ -n $quiet ]] && disp I "Your version is up-to-date." + [[ $quiet != 1 ]] && disp I "Your version is up-to-date." result=0 fi rm -f $vfile @@ -71,12 +97,38 @@ check_updates() unset lastver vfile return $result } +# ------------------------------------------------------------------------------ + # ------------------------------------------------------------------------------ # Apply update to profile -# ------------------------------------------------------------------------------ +# Usage: profile_upgrade profile_upgrade() { + local PARSED=$(getopt -o h --long help -n 'profile_upgrade' -- "$@") + if [[ $? -ne 0 ]]; then + printf "Invalid options, use \"profile_upgrade --help\" to display usage." + return 1 + fi + eval set -- "$PARSED" + while true; do + case "$1" in + -h|--help) + printf "profile_upgrade: Upgrade the profile to the latest version.\n\n" + printf "Usage: profile_upgrade\n" + return 0 + ;; + --) + shift + break + ;; + *) + disp E "Invalid options, use \"profile_upgrade --help\" to display usage." + return 1 + ;; + esac + done + if check_updates -q; then disp "No update available." return 0 @@ -130,4 +182,7 @@ profile_upgrade() rm -rf "$tmpdir" fi } +# ------------------------------------------------------------------------------ + + # EOF diff --git a/version b/version index 9575d51..f76c0c7 100644 --- a/version +++ b/version @@ -1 +1 @@ -3.6.1 +3.90.1-4_alpha_1