diff --git a/profile.d/compress.sh b/profile.d/compress.sh new file mode 100644 index 0000000..4d6df4f --- /dev/null +++ b/profile.d/compress.sh @@ -0,0 +1,324 @@ +# ------------------------------------------------------------------------------ +# Smartly uncompress archives (zip only) +# ------------------------------------------------------------------------------ +utaz() +{ + 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 + return 0 + ;; + + "-d"|"--delete") + local willrm=1 + ;; + + "-c"|"--create-dir") + local createdir=1 + ;; + + "-n"|"--no-dir") + local nodir=1 + ;; + + "-"*) + echo "Invalid option, use \"utaz --help\" to display options list" + echo + return 1 + ;; + + *) + # The ${opt%/} writing is to remove trailing / if any + local LIST="$LIST ${opt%/}" + ;; + esac + done + + [[ $createdir && $nodir ]] && echo "*** Error: --create-dir and --no-dir options are mutually exclusive." + + [[ ! $LIST ]] && local LIST="." + + for zitem in $LIST; do + [[ $(ls $zitem/*.zip 2> /dev/null | wc -l) -eq 0 ]] && + echo "$zitem contains no supported archive file, skipping." && + continue + + for f in $zitem/*.zip; do + echo -n "Processing archive $zitem/$f... " + local dir=${f::-4} + + mkdir -p $dir + [[ $? -gt 0 ]] && + echo "[ filesystem can't create directories, exit ]" && + return 1 + + unzip -o $f -d $dir > /dev/null 2>&1 + case $? in + 0) + [[ $willrm ]] && rm -f $f && echo -n "Deleted ! " + ;; + + 1) + echo "No deletion on warnings " + ;; + *) + echo "[ zip file corrupted, failed ]" + rm -rf $dir > /dev/null 2>&1 + continue + ;; + esac + + if [[ $createdir ]]; then + echo -n "[ subdir created, " + elif [[ $nodir ]]; then + mv ./$dir/* ./ && rmdir $dir + echo -n "[ No subdir, " + else + subdirs=$(find $dir -maxdepth 1 | wc -l) + if [[ $subdirs -eq 2 ]]; then + mv ./$dir/* ./ && rmdir $dir + echo -n "[ No subdir, " + else + echo -n "[ subdir created, " + fi + fi + echo " OK ]" + done + done +} +export -f utaz + +# ------------------------------------------------------------------------------ +# Compress directories or files into one or more archive +# ------------------------------------------------------------------------------ +taz () +{ + _doxz() + { + command -v xz >/dev/null 2>&1 || { + echo -e >&2 "\t*** The program 'xz' is not installed, aborting." + return 127 + } + + [[ $4 ]] && local verb='-v' + + # Display a warning for this format + echo -e "\t! Warning: xz format is not suited for long term archiving." + echo -e "\t See https://www.nongnu.org/lzip/xz_inadequate.html for details." + + # Compresse to xz (lzma2) - Deprecated + xz $verb --compress --keep -$3 -T $2 $1 + return $? + } + + _dolz() + { + local procopt="--threads $2" + local command=plzip + + command -v plzip >/dev/null 2>&1 || { + command -v lzip >/dev/null 2>&1 || { + echo -e >&2 "\t*** Program 'plzip' or 'lzip' are not installed, aborting." + return 127 + } + local command=lzip + local procopt="" + [[ $2 -gt 1 ]] && + echo -e "\t! Warning: lzip doesn't support multithreading, falling back to 1 thread." && + echo -e "\t* Consitder installing plzip to obtain multithreading abilities." + } + + [[ $4 ]] && local verb="-vv" + + # Compresse au format lzip (lzma) + $command $verb $procopt --keep -$3 $1 + return $? + } + + _dogz() + { + local procopt="--processes $2" + local command=pigz + + command -v pigz >/dev/null 2>&1 || { + command -v gzip >/dev/null 2>&1 || { + echo -e >&2 "\t*** Programs 'pigz' or 'gzip' are not installed, aborting." + return 127 + } + local command="gzip --compress" + local procopt="" + [[ $2 -gt 1 ]] && + echo -e "\t! Warning: gzip doesn't support multithreading, falling back to 1 thread." && + echo -e "\t* Consitder installing pigz to obtain multithreading abilities." + } + + [[ $4 ]] && local verb="--verbose" + + # Compresse au format bz2 + $command $verb $procopt --keep -$3 $1 + return $? + } + + _dobz2() + { + local procopt="-p$2" + local command=pbzip2 + + command -v pbzip2 >/dev/null 2>&1 || { + command -v bzip2 >/dev/null 2>&1 || { + echo -e >&2 "\t*** The program 'pbzip2' or 'bzip2' are not installed, aborting." + return 127 + } + local command=bzip2 + local procopt="" + [[ $2 -gt 1 ]] && + echo -e "\t! Warning: bzip2 doesn't support multithreading, falling back to 1 thread." && + echo -e "\t* Consitder installing pbzip2 to obtain multithreading abilities." + } + + [[ $4 ]] && local verb="-v" + + # Compresse au format bz2 + $command $verb --compress $procopt --keep -$3 $1 + return $? + } + + _dolzo() + { + command -v lzop >/dev/null 2>&1 || { + echo -e >&2 "\t*** The program 'lzop' is not installed, aborting." + return 127 + } + + [[ $4 ]] && local verb='-v' + [[ $2 -gt 1 ]] && echo -e "\t! Warning: lzop doesn't support multithreading, falling back to 1 thread." + + # Compresse au format lzo + lzop --keep -$3 $1 + 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 " -1, .., -9 Compression level to use [1=fast/big, 9=slow/small]" + 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 + return 0 + ;; + + "-d"|"--delete") + local willrm=1 + ;; + + "-f"?*|"--format"?*) + local compform=$(echo "$opt" | cut -f 2- -d '=') + ;; + + "-p"?*|"--parallel"?*) + local nproc=$(echo "$opt" | cut -f 2- -d '=') + ;; + + "-v"|"--verbose") + local verbose=1 + ;; + + "-"[1..9]) + local complevel=${opt:1:1} + ;; + + "-"*) + echo "Invalid option, use taz --help to display options list" + echo + return 1 + ;; + + *) + local LIST="$LIST ${opt%/}" + ;; + esac + done + + [[ ! $compform ]] && compform=lz # safe and efficient (unless data are already compressed) + [[ ! $nproc ]] && nproc=1 + [[ ! $complevel ]] && complevel=6 + + for item in $LIST; do + local donetar=0 + echo "--- Processing $item..." + + if [[ -d $item ]]; then + echo -ne "\t* Creating $item.tar... " + + tar -cf $item{.tar,} + if [[ ! $? -eq 0 ]]; then + echo "[ failed, skipping ]" + continue + fi + + local donetar=1 + echo "[ OK ]" + fi + + local fname=$item + [[ $donetar -gt 0 ]] && fname=$item.tar + + # Skip compression part if tar is asked + if [[ $compform != "tar" ]]; then + echo -e "\t* Compressing archive..." + _do$compform $fname $nproc $complevel $verbose + [[ ! $? -eq 0 ]] && case $? in + 127) + echo -e "\t*** Compression program unavailable, aborting." + return 127 + ;; + *) + echo -e "\t*** Compression program returned an error, not deleting anything if asked, skipping to next item." + continue + ;; + esac + + [[ $donetar -gt 0 ]] && rm $fname + fi + + if [[ $willrm ]]; then + echo -en "\t* Deleting original source as asked... " + rm -r $item && echo '[ OK ]' || echo '[ failed ]' + fi + + echo "--- Done" + done + +} +export -f taz diff --git a/profile.d/debug.sh b/profile.d/debug.sh new file mode 100644 index 0000000..81b3af9 --- /dev/null +++ b/profile.d/debug.sh @@ -0,0 +1,72 @@ +# ------------------------------------------------------------------------------ +# Display a 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 + done + unset func i + echo "==============================" +} + +# ------------------------------------------------------------------------------ +# Function to be trapped for errors investigation +# ------------------------------------------------------------------------------ +function error () +{ + local errcode=$? + backtrace + exit $errcode +} + + +# ------------------------------------------------------------------------------ +# Activate or deactivate error trapping to display backtrace +# ------------------------------------------------------------------------------ +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 + ;; + "--on") + if [[ $status == "on" ]]; then + echo "Warning: ERR signal trap is already set, replacing previous trap!" + fi + trap "error" ERR + ;; + "--off") + if [[ $status != "on" ]]; then + echo "Warning: ERR signal trap is already unset!" + fi + trap - ERR + ;; + "--status") + echo "ERR trap signal is ${status}." + ;; + esac + done + unset status +} +export -f settrace diff --git a/profile.d/filefct.sh b/profile.d/filefct.sh new file mode 100644 index 0000000..33e1dba --- /dev/null +++ b/profile.d/filefct.sh @@ -0,0 +1,171 @@ +# ------------------------------------------------------------------------------ +# expandlist : treat wildcards in a file/directory list +# ------------------------------------------------------------------------------ +expandlist() +{ + local result="" + for item in "$1"; do + for content in "$item"; do + result+="\"$content\" " + done + done + echo $result +} + + +# ------------------------------------------------------------------------------ +# Clean a directory or a tree from temporary or backup files +# ------------------------------------------------------------------------------ +clean () +{ + for opt in $@ ; do + case $opt in + "-r"|"--recurs") + local recursive=1 + ;; + + "-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 + ;; + + "-s"|"--shell") + local outshell=1 + ;; + + "-f"|"--force") + local force=1 + ;; + + "-"*) + echo "Invalid option, use \"clean --help\" to display usage." + echo + return 1 + ;; + + *) + local dirlist="$dirlist $opt" + ;; + esac + done + + [[ ! $dirlist ]] && local dirlist=$(pwd) + + [[ ! $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 + if [[ ! $outshell ]]; then + rm $rmopt $f + else + echo "rm $rmopt $f" + fi + done + done + unset outshell dirlist dellist findopt rmopt +} +export -f clean + + +# ------------------------------------------------------------------------------ +# Create a directory then goes inside +# ------------------------------------------------------------------------------ +mcd () +{ + if [[ ! $# -eq 1 ]] ; then + echo "Create a directory then goes inside." + echo "Usage: mcd " + return 1 + fi + mkdir -pv $1 && cd $1 +} +export -f mcd + + +# ------------------------------------------------------------------------------ +# Rename all files in current directory to replace spaces with _ +# ------------------------------------------------------------------------------ +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 what is being done" + echo " -s, --shell Do nothing and display commands that would be executed" + echo + return 0 + ;; + + "-r"|"--recursive") + local recurs=1 + ;; + + "-c"?*|"--subst-char"?*) + local substchar=$(echo "$opt" | cut -f 2- -d '=') + ;; + + "-v"|"--verbose") + local verb=1 + ;; + + "-s"|"--shell") + local shell=1 + ;; + + *) + echo "Invalid parameter, use \"rmspc --help\" to display options list" + echo + return 1 + ;; + esac + done + + [[ ! $substchar ]] && substchar="_" + [[ $verb ]] && local mvopt="-v" + + for f in *; do + [[ $recurs ]] && [[ -d "$f" ]] && ( + [[ $verb ]] && echo "-- Entering directory $(pwd)/$f ..." + local lastdir=$f + pushd "$f" > /dev/null + rmspc $@ + popd > /dev/null + [[ $verb ]] && echo "-- Leaving directory $(pwd)/$lastdir" + unset lastdir + ) + + if [[ $(echo $f | grep " ") ]]; then + local newf="${f// /${substchar}}" + local command="mv $mvopt \"$f\" \"$newf\"" + if [[ $shell ]]; then + echo $command + else + $command + fi + fi + done + unset lst substchar verb shell newf command mvopt +} +export -f rmspc diff --git a/profile.d/help.sh b/profile.d/help.sh new file mode 100644 index 0000000..ca92c12 --- /dev/null +++ b/profile.d/help.sh @@ -0,0 +1,31 @@ +# ------------------------------------------------------------------------------ +# Display list of commands and general informations +# ------------------------------------------------------------------------------ +help () +{ + cat </dev/null 2>&1; then + figlet -k $(hostname) + else + echo "$(hostname -f)" + fi + echo "" + if command -v neofetch >/dev/null 2>&1; then + neofetch + else + ( + if [[ -s /etc/os-release ]]; then + . /etc/os-release + echo "$NAME $VERSION" + else + cat /proc/version + fi + echo "Uptime: $(uptime)" + ) + fi +} +export -f showinfo diff --git a/profile.d/lang.sh b/profile.d/lang.sh new file mode 100644 index 0000000..70c8912 --- /dev/null +++ b/profile.d/lang.sh @@ -0,0 +1,35 @@ +# ------------------------------------------------------------------------------ +# Change locale to French +# ------------------------------------------------------------------------------ +setfr () +{ + # Set fr locale definitions + export LANG=fr_FR.UTF-8 + export LC_MESSAGES=fr_FR.UTF-8 + export LC_ALL=fr_FR.UTF-8 +} +export -f setfr + +# ------------------------------------------------------------------------------ +# Change locale to C standard +# ------------------------------------------------------------------------------ +setc () +{ + # Locale definitions + export LANG=C + export LC_MESSAGES=C + export LC_ALL=C +} +export -f setc + +# ------------------------------------------------------------------------------ +# Change locale to US (needed by Steam) +# ------------------------------------------------------------------------------ +setus () +{ + # Locale definitions + export LANG=en_US.UTF-8 + export LC_MESSAGES=en_US.UTF-8 + export LC_ALL=en_US.UTF-8 +} +export -f setus diff --git a/profile.d/net.sh b/profile.d/net.sh new file mode 100644 index 0000000..3b7d6b0 --- /dev/null +++ b/profile.d/net.sh @@ -0,0 +1,49 @@ +# ------------------------------------------------------------------------------ +# Determine if parameter is a valid IPv4 address +# ------------------------------------------------------------------------------ +isipv4 () +{ + # Set up local variables + local ip=$1 + + # Start with a regex format test + if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then + local old_ifs=$IFS + IFS="." + ip=($ip) + IFS=$old_ifs + if [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \ + && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]; then + if [[ -t 1 ]]; then + echo "The given IPv4 is valid." + fi + return 0 + fi + fi + if [[ -t 1 ]]; then + echo "The given parameter is NOT a valid IPv4." + fi + return 1 +} +export -f isipv4 + + +# ------------------------------------------------------------------------------ +# Determine if parameter is a valid IPv4 address +# ------------------------------------------------------------------------------ +isipv6 () +{ + local ip="$1" + local regex='^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$' + if [[ $ip =~ $regex ]]; then + if [[ -t 1 ]]; then + echo "The given IPv6 is valid." + fi + return 0 + fi + if [[ -t 1 ]]; then + echo "The given parameter is not a valid IPv6." + fi + return 1 +} +export -f isipv6 diff --git a/profile.d/packages.sh b/profile.d/packages.sh new file mode 100644 index 0000000..1980333 --- /dev/null +++ b/profile.d/packages.sh @@ -0,0 +1,42 @@ +# ------------------------------------------------------------------------------ +# Look for a package within installed one +# ------------------------------------------------------------------------------ +dpkgs () +{ + 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 + ;; + + "-"*) + echo "Invalid option, use \"dpkgs --help\" to display usage." + echo + return 1 + ;; + + *) + local pkg=$1 && shift + count=$(( $count + 1 )) + [[ $count -gt 1 ]] && + echo "*** Error: Please specify a package name, without space, eventually partial." && + return 1 + + ;; + esac + done + [[ $count -lt 1 ]] && + echo "*** Error: Please specify a package name, without space, eventually partial." && + return 1 + + [[ -x /usr/sbin/dpkg ]] && + echo "*** Error: dpkg command seems unavialable." && + return 2 + + dpkg -l | grep $pkg +} +export -f dpkgs diff --git a/profile.d/processes.sh b/profile.d/processes.sh new file mode 100644 index 0000000..a484887 --- /dev/null +++ b/profile.d/processes.sh @@ -0,0 +1,40 @@ +# ------------------------------------------------------------------------------ +# Search processes matching the given string +# ------------------------------------------------------------------------------ +ppg () +{ + ps -edf | grep $@ | grep -v "grep $@" +} +export -f ppg + + +# ------------------------------------------------------------------------------ +# Get PID list of the given process name +# ------------------------------------------------------------------------------ +gpid () +{ + [[ $UID -eq 0 ]] && local psopt="-A" + [[ $# -eq 1 ]] && local single=1 + for pid in $@; do + local result=$(ps $psopt | grep $pid | awk '{print $1}' | sed "s/\n/ /") + if [[ $single ]]; then + [[ $result ]] && echo "${result//$'\n'/ }" + else + [[ $result ]] && echo "$pid: ${result//$'\n'/ }" + fi + done + [[ $result ]] || return 1 +} +export -f gpid + + +# ------------------------------------------------------------------------------ +# Kill all processes owned by the given users +# ------------------------------------------------------------------------------ +ku () +{ + for u in $@; do + killall -u $u + done +} +export -f ku diff --git a/profile.d/prompt.sh b/profile.d/prompt.sh new file mode 100644 index 0000000..9b136b8 --- /dev/null +++ b/profile.d/prompt.sh @@ -0,0 +1,90 @@ +# ------------------------------------------------------------------------------ +# timer_* functions : internal timing function for prompt +# ------------------------------------------------------------------------------ +function timer_now +{ + date +%s%N +} + +function timer_start +{ + timer_start=${timer_start:-$(timer_now)} +} + +function timer_stop +{ + local delta_us=$((($(timer_now) - $timer_start) / 1000)) + local us=$((delta_us % 1000)) + local ms=$(((delta_us / 1000) % 1000)) + local s=$(((delta_us / 1000000) % 60)) + local m=$(((delta_us / 60000000) % 60)) + local h=$((delta_us / 3600000000)) + # Goal: always show around 3 digits of accuracy + if ((h > 0)); then + timer_show=${h}h${m}m + elif ((m > 0)); then + timer_show=${m}m${s}s + elif ((s >= 10)); then + timer_show=${s}.$((ms / 100))s + elif ((s > 0)); then + timer_show=${s}.$(printf %03d $ms)s + elif ((ms >= 100)); then + timer_show=${ms}ms + elif ((ms > 0)); then + timer_show=${ms}.$((us / 100))ms + else + timer_show=${us}us + fi + unset timer_start +} + +# ------------------------------------------------------------------------------ +# Function triguered internaly by bash : defining prompt +# ------------------------------------------------------------------------------ +set_prompt () +{ + Last_Command=$? # Must come first! + Blue='\[\e[0;34m\]' + White='\[\e[01;37m\]' + Yellow='\[\e[01;93m\]' + Red='\[\e[01;31m\]' + Green='\[\e[01;32m\]' + OnGrey='\[\e[47m\]' + OnRed='\[\e[41m\]' + OnBlue='\[\e[44m\]' + ICyan='\[\e[0;96m\]' + Default='\[\e[00m\]' + FancyX='\342\234\227' + Checkmark='\342\234\223' + + # Begin with time + PS1="\[\e[s$Blue$OnGrey [ \t ] $OnBlue" + + # Add a bright white exit status for the last command + + # If it was successful, print a green check mark. Otherwise, print + # a red X. + if [[ $Last_Command == 0 ]]; then + PS1+="$White$OnBlue [ \$Last_Command " + PS1+="$Green$Checkmark " + else + PS1+="$White$OnRed [ \$Last_Command " + PS1+="$Yellow$FancyX " + fi + + # Add the ellapsed time and current date + timer_stop + PS1+="($timer_show)$White ] $OnBlue " + + # If root, just print the host in red. Otherwise, print the current user + # and host in green. + if [[ $EUID -eq 0 ]]; then + PS1+="$Red\\u$Green@\\h" + else + PS1+="$Green\\u@\\h" + fi + PS1+="\e[K\e[u$Default\n" + # Print the working directory and prompt marker in blue, and reset + # the text color to the default. + PS1+="$ICyan\\w \\\$$Default " +} diff --git a/profile.d/rain.sh b/profile.d/rain.sh new file mode 100644 index 0000000..b60c53d --- /dev/null +++ b/profile.d/rain.sh @@ -0,0 +1,119 @@ +# ------------------------------------------------------------------------------ +# Let the rain fall +# ------------------------------------------------------------------------------ +rain() +{ + local exit_st=0 + local rain_cars=("|" "│" "┃" "┆" "┇" "┊" "┋" "╽" "╿") + local rain_colors=("\e[37m" "\e[37;1m") + # More from 256 color mode + for i in {244..255}; do + rain_colors=( "${rain_colors[@]}" "\e[38;5;${i}m" ) + done + local rain_tab=${#rain_cars[@]} + local rain_color_tab=${#rain_colors[@]} + local num_rain_metadata=5 + local term_height=$(tput lines) + local term_width=$(tput cols) + local step_duration=0.050 + local X=0 Y=0 drop_length=0 rain_drop=0 + local max_rain_width=0 new_rain_odd=0 falling_odd=0 + + + sigwinch() { + term_width=$(tput cols) + term_height=$(tput lines) + #step_duration=0.025 + (( max_rain_width = term_width * term_height / 4 )) + (( max_rain_height = term_height < 10 ? 1 : term_height / 10 )) + # In percentage + (( new_rain_odd = term_height > 50 ? 100 : term_height * 2 )) + (( new_rain_odd = new_rain_odd * 75 / 100 )) + (( falling_odd = term_height > 25 ? 100 : term_height * 4 )) + (( falling_odd = falling_odd * 90 / 100 )) + } + + do_exit() { + exit_st=1 + } + + do_render() { + # Clean screen first + local idx=0 + for ((idx = 0; idx < num_rains * num_rain_metadata; idx += num_rain_metadata)); do + X=${rains[idx]} + Y=${rains[idx + 1]} + 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 " + done + done + + for ((idx = 0; idx < num_rains * num_rain_metadata; idx += num_rain_metadata)); do + if (( 100 * RANDOM / 32768 < falling_odd )); then + # Falling + if (( ++rains[idx + 1] > term_height )); then + # Out of screen, bye sweet <3 + rains=("${rains[@]:0:idx}" + "${rains[@]:idx+num_rain_metadata:num_rains*num_rain_metadata}") + (( num_rains-- )) + continue + fi + fi + X=${rains[idx]} + Y=${rains[idx + 1]} + rain_drop=${rains[idx + 2]} + drop_color=${rains[idx + 3]} + 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}" + done + done + } + + trap do_exit TERM INT + trap sigwinch WINCH + # No echo stdin and hide the cursor + stty -echo + echo -ne "\e[?25l" + + echo -ne "\e[2J" + local rains=() + local num_rains=0 + sigwinch + while (( exit_st <= 0 )); do + if (( $exit_st <=0 )); then + read -n 1 -t $step_duration ch + case "$ch" in + q|Q) + do_exit + ;; + esac + + if (( num_rains < max_rain_width )) && (( 100 * RANDOM / 32768 < new_rain_odd )); then + # Need new |, 1-based + rain_drop="${rain_cars[rain_tab * RANDOM / 32768]}" + drop_color="${rain_colors[rain_color_tab * RANDOM / 32768]}" + drop_length=$(( max_rain_height * RANDOM / 32768 + 1 )) + X=$(( term_width * RANDOM / 32768 + 1 )) + Y=$(( 1 - drop_length )) + rains=( "${rains[@]}" "$X" "$Y" "$rain_drop" "$drop_color" "$drop_length" ) + (( num_rains++ )) + fi + + # Let rain fall! + do_render + fi + done + echo -ne "\e[${term_height};1H\e[0K" + + # Show cursor and echo stdin + echo -ne "\e[?25h" + stty echo + unset exit_st + trap - TERM INT + trap - WINCH +} +export -f rain diff --git a/profile.d/ssh.sh b/profile.d/ssh.sh new file mode 100644 index 0000000..a60673c --- /dev/null +++ b/profile.d/ssh.sh @@ -0,0 +1,70 @@ +# ------------------------------------------------------------------------------ +# Remove host from know_host (name and IP) for the active user +# ------------------------------------------------------------------------------ +rmhost () +{ + if [[ "$#" -lt 1 ]]; then + echo "Error: incorrect number of parameters." + echo "Usage: rmhost [hostname2|ip2 [...]]" + return 1 + fi + + while [[ $1 ]]; do + local hst=$1 && shift + isipv4 $hst > /dev/null + local v4=$? + isipv6 $hst > /dev/null + local v6=$? + + if [[ $v4 -eq 0 || $v6 -eq 0 ]]; then + local ip=$hst + unset hst + fi + unset v4 v6 + + if [[ ! $ip && $hst ]]; then + ip=$(host $hst | grep "has address" | awk '{print $NF}') + [[ ! $? ]] && + echo "*** rmhost(): Error extracting IP from hostname." && + return 1 + fi + + if [[ $hst ]]; then + echo "Removing host $hst from ssh known_host..." + ssh-keygen -R $hst > /dev/null + fi + if [[ $ip ]]; then + echo "Removing IP $ip from ssh known_host..." + ssh-keygen -R $ip > /dev/null + fi + unset hst ip + done +} +export -f rmhost + + +# ------------------------------------------------------------------------------ +# Login root via SSH on the given machine +# ------------------------------------------------------------------------------ +ssr () +{ + for opt in $@ ; do + case $opt in + "-h"|"--help") + echo "ssr: do a root user ssh login." + echo + echo "Usage: ssr " + return 0 + ;; + esac + done + + [[ ! $1 ]] && + echo "Please specify the server you want to log in." && + return 1 + + local srv=$1 && shift + + ssh -Y root@$srv $@ +} +export -f ssr diff --git a/profile.sh b/profile.sh index 33535be..6568c65 100644 --- a/profile.sh +++ b/profile.sh @@ -32,6 +32,7 @@ # 24/06/2022 v2.8.0 : Added backtrace, error and settrace, corrected showinfo # 19/07/2022 v2.8.1 : few cleanup, fixes and optimizations # 29/07/2022 v2.8.2 : added warning for non bash users +# 27/08/2022 v3.0.0 : splitted everything, added rain screensaver # ------------------------------------------------------------------------------ # Copyright (c) 2013-2022 Geoffray Levasseur # Protected by the BSD3 license. Please read bellow for details. @@ -67,7 +68,7 @@ # * OF SUCH DAMAGE. # ------------------------------------------------------------------------------ -export PROFVERSION="2.8.2" +export PROFVERSION="3.0.0" export DEFAULT_CITY="Toulouse" @@ -108,1096 +109,6 @@ pathappend () export $pathvar="${!pathvar:+${!pathvar}:}$1" } -# ------------------------------------------------------------------------------ -# expandlist : treat wildcards in a file/directory list -# ------------------------------------------------------------------------------ -expandlist() -{ - local result="" - for item in "$1"; do - for content in "$item"; do - result+="\"$content\" " - done - done - echo $result -} - -# ------------------------------------------------------------------------------ -# timer_* functions : internal timing function for prompt -# ------------------------------------------------------------------------------ -function timer_now -{ - date +%s%N -} - -function timer_start -{ - timer_start=${timer_start:-$(timer_now)} -} - -function timer_stop -{ - local delta_us=$((($(timer_now) - $timer_start) / 1000)) - local us=$((delta_us % 1000)) - local ms=$(((delta_us / 1000) % 1000)) - local s=$(((delta_us / 1000000) % 60)) - local m=$(((delta_us / 60000000) % 60)) - local h=$((delta_us / 3600000000)) - # Goal: always show around 3 digits of accuracy - if ((h > 0)); then - timer_show=${h}h${m}m - elif ((m > 0)); then - timer_show=${m}m${s}s - elif ((s >= 10)); then - timer_show=${s}.$((ms / 100))s - elif ((s > 0)); then - timer_show=${s}.$(printf %03d $ms)s - elif ((ms >= 100)); then - timer_show=${ms}ms - elif ((ms > 0)); then - timer_show=${ms}.$((us / 100))ms - else - timer_show=${us}us - fi - unset timer_start -} - -# ------------------------------------------------------------------------------ -# Function triguered internaly by bash : defining prompt -# ------------------------------------------------------------------------------ -set_prompt () -{ - Last_Command=$? # Must come first! - Blue='\[\e[0;34m\]' - White='\[\e[01;37m\]' - Yellow='\[\e[01;93m\]' - Red='\[\e[01;31m\]' - Green='\[\e[01;32m\]' - OnGrey='\[\e[47m\]' - OnRed='\[\e[41m\]' - OnBlue='\[\e[44m\]' - ICyan='\[\e[0;96m\]' - Default='\[\e[00m\]' - FancyX='\342\234\227' - Checkmark='\342\234\223' - - # Begin with time - PS1="\[\e[s$Blue$OnGrey [ \t ] $OnBlue" - - # Add a bright white exit status for the last command - - # If it was successful, print a green check mark. Otherwise, print - # a red X. - if [[ $Last_Command == 0 ]]; then - PS1+="$White$OnBlue [ \$Last_Command " - PS1+="$Green$Checkmark " - else - PS1+="$White$OnRed [ \$Last_Command " - PS1+="$Yellow$FancyX " - fi - - # Add the ellapsed time and current date - timer_stop - PS1+="($timer_show)$White ] $OnBlue " - - # If root, just print the host in red. Otherwise, print the current user - # and host in green. - if [[ $EUID -eq 0 ]]; then - PS1+="$Red\\u$Green@\\h" - else - PS1+="$Green\\u@\\h" - fi - PS1+="\e[K\e[u$Default\n" - # Print the working directory and prompt marker in blue, and reset - # the text color to the default. - PS1+="$ICyan\\w \\\$$Default " -} - -# ------------------------------------------------------------------------------ -# Show profile version -# ------------------------------------------------------------------------------ -ver () -{ - echo "Profile version $PROFVERSION." -} -export -f ver - -# ------------------------------------------------------------------------------ -# Determine if parameter is a valid IPv4 address -# ------------------------------------------------------------------------------ -isipv4 () -{ - # Set up local variables - local ip=$1 - - # Start with a regex format test - if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then - local old_ifs=$IFS - IFS="." - ip=($ip) - IFS=$old_ifs - if [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \ - && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]; then - if [[ -t 1 ]]; then - echo "The given IPv4 is valid." - fi - return 0 - fi - fi - if [[ -t 1 ]]; then - echo "The given parameter is NOT a valid IPv4." - fi - return 1 -} -export -f isipv4 - -# ------------------------------------------------------------------------------ -# Determine if parameter is a valid IPv4 address -# ------------------------------------------------------------------------------ -isipv6 () -{ - local ip="$1" - local regex='^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$' - if [[ $ip =~ $regex ]]; then - if [[ -t 1 ]]; then - echo "The given IPv6 is valid." - fi - return 0 - fi - if [[ -t 1 ]]; then - echo "The given parameter is not a valid IPv6." - fi - return 1 -} -export -f isipv6 - - -# ------------------------------------------------------------------------------ -# Change locale to French -# ------------------------------------------------------------------------------ -setfr () -{ - # Set fr locale definitions - export LANG=fr_FR.UTF-8 - export LC_MESSAGES=fr_FR.UTF-8 - export LC_ALL=fr_FR.UTF-8 -} -export -f setfr - -# ------------------------------------------------------------------------------ -# Change locale to C standard -# ------------------------------------------------------------------------------ -setc () -{ - # Locale definitions - export LANG=C - export LC_MESSAGES=C - export LC_ALL=C -} -export -f setc - -# ------------------------------------------------------------------------------ -# Change locale to US (needed by Steam) -# ------------------------------------------------------------------------------ -setus () -{ - # Locale definitions - export LANG=en_US.UTF-8 - export LC_MESSAGES=en_US.UTF-8 - export LC_ALL=en_US.UTF-8 -} -export -f setus - -# ------------------------------------------------------------------------------ -# Display weather of the given city (or default one) -# ------------------------------------------------------------------------------ -meteo () -{ - cities=$@ - [[ $# -eq 0 ]] && local cities=$DEFAULT_CITY - - for city in $cities; do - curl https://wttr.in/$city - done -} -export -f meteo - -# ------------------------------------------------------------------------------ -# Clean a directory or a tree from temporary or backup files -# ------------------------------------------------------------------------------ -clean () -{ - for opt in $@ ; do - case $opt in - "-r"|"--recurs") - local recursive=1 - ;; - - "-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 - ;; - - "-s"|"--shell") - local outshell=1 - ;; - - "-f"|"--force") - local force=1 - ;; - - "-"*) - echo "Invalid option, use \"clean --help\" to display usage." - echo - return 1 - ;; - - *) - local dirlist="$dirlist $opt" - ;; - esac - done - - [[ ! $dirlist ]] && local dirlist=$(pwd) - - [[ ! $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 - if [[ ! $outshell ]]; then - rm $rmopt $f - else - echo "rm $rmopt $f" - fi - done - done - unset outshell dirlist dellist findopt rmopt -} -export -f clean - -# ------------------------------------------------------------------------------ -# Login root via SSH on the given machine -# ------------------------------------------------------------------------------ -ssr () -{ - for opt in $@ ; do - case $opt in - "-h"|"--help") - echo "ssr: do a root user ssh login." - echo - echo "Usage: ssr " - return 0 - ;; - esac - done - - [[ ! $1 ]] && - echo "Please specify the server you want to log in." && - return 1 - - local srv=$1 && shift - - ssh -Y root@$srv $@ -} -export -f ssr - -# ------------------------------------------------------------------------------ -# Look for a package within installed one -# ------------------------------------------------------------------------------ -dpkgs () -{ - 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 - ;; - - "-"*) - echo "Invalid option, use \"dpkgs --help\" to display usage." - echo - return 1 - ;; - - *) - local pkg=$1 && shift - count=$(( $count + 1 )) - [[ $count -gt 1 ]] && - echo "*** Error: Please specify a package name, without space, eventually partial." && - return 1 - - ;; - esac - done - [[ $count -lt 1 ]] && - echo "*** Error: Please specify a package name, without space, eventually partial." && - return 1 - - [[ -x /usr/sbin/dpkg ]] && - echo "*** Error: dpkg command seems unavialable." && - return 2 - - dpkg -l | grep $pkg -} -export -f dpkgs - -# ------------------------------------------------------------------------------ -# Search processes matching the given string -# ------------------------------------------------------------------------------ -ppg () -{ - ps -edf | grep $@ | grep -v "grep $@" -} -export -f ppg - -# ------------------------------------------------------------------------------ -# Create a directory then goes inside -# ------------------------------------------------------------------------------ -mcd () -{ - if [[ ! $# -eq 1 ]] ; then - echo "Create a directory then goes inside." - echo "Usage: mcd " - return 1 - fi - mkdir -pv $1 && cd $1 -} -export -f mcd - -# ------------------------------------------------------------------------------ -# Get PID list of the given process name -# ------------------------------------------------------------------------------ -gpid () -{ - [[ $UID -eq 0 ]] && local psopt="-A" - [[ $# -eq 1 ]] && local single=1 - for pid in $@; do - local result=$(ps $psopt | grep $pid | awk '{print $1}' | sed "s/\n/ /") - if [[ $single ]]; then - [[ $result ]] && echo "${result//$'\n'/ }" - else - [[ $result ]] && echo "$pid: ${result//$'\n'/ }" - fi - done - [[ $result ]] || return 1 -} -export -f gpid - - -# ------------------------------------------------------------------------------ -# Remove host from know_host (name and IP) for the active user -# ------------------------------------------------------------------------------ -rmhost () -{ - if [[ "$#" -lt 1 ]]; then - echo "Error: incorrect number of parameters." - echo "Usage: rmhost [hostname2|ip2 [...]]" - return 1 - fi - - while [[ $1 ]]; do - local hst=$1 && shift - isipv4 $hst > /dev/null - local v4=$? - isipv6 $hst > /dev/null - local v6=$? - - if [[ $v4 -eq 0 || $v6 -eq 0 ]]; then - local ip=$hst - unset hst - fi - unset v4 v6 - - if [[ ! $ip && $hst ]]; then - ip=$(host $hst | grep "has address" | awk '{print $NF}') - [[ ! $? ]] && - echo "*** rmhost(): Error extracting IP from hostname." && - return 1 - fi - - if [[ $hst ]]; then - echo "Removing host $hst from ssh known_host..." - ssh-keygen -R $hst > /dev/null - fi - if [[ $ip ]]; then - echo "Removing IP $ip from ssh known_host..." - ssh-keygen -R $ip > /dev/null - fi - unset hst ip - done -} -export -f rmhost - - -# ------------------------------------------------------------------------------ -# Rename all files in current directory to replace spaces with _ -# ------------------------------------------------------------------------------ -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 what is being done" - echo " -s, --shell Do nothing and display commands that would be executed" - echo - return 0 - ;; - - "-r"|"--recursive") - local recurs=1 - ;; - - "-c"?*|"--subst-char"?*) - local substchar=$(echo "$opt" | cut -f 2- -d '=') - ;; - - "-v"|"--verbose") - local verb=1 - ;; - - "-s"|"--shell") - local shell=1 - ;; - - *) - echo "Invalid parameter, use \"rmspc --help\" to display options list" - echo - return 1 - ;; - esac - done - - [[ ! $substchar ]] && substchar="_" - [[ $verb ]] && local mvopt="-v" - - for f in *; do - [[ $recurs ]] && [[ -d "$f" ]] && ( - [[ $verb ]] && echo "-- Entering directory $(pwd)/$f ..." - local lastdir=$f - pushd "$f" > /dev/null - rmspc $@ - popd > /dev/null - [[ $verb ]] && echo "-- Leaving directory $(pwd)/$lastdir" - unset lastdir - ) - - if [[ $(echo $f | grep " ") ]]; then - local newf="${f// /${substchar}}" - local command="mv $mvopt \"$f\" \"$newf\"" - if [[ $shell ]]; then - echo $command - else - $command - fi - fi - done - unset lst substchar verb shell newf command mvopt -} -export -f rmspc - -# ------------------------------------------------------------------------------ -# Smartly uncompress archives (zip only) -# ------------------------------------------------------------------------------ -utaz() -{ - 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 - return 0 - ;; - - "-d"|"--delete") - local willrm=1 - ;; - - "-c"|"--create-dir") - local createdir=1 - ;; - - "-n"|"--no-dir") - local nodir=1 - ;; - - "-"*) - echo "Invalid option, use \"utaz --help\" to display options list" - echo - return 1 - ;; - - *) - # The ${opt%/} writing is to remove trailing / if any - local LIST="$LIST ${opt%/}" - ;; - esac - done - - [[ $createdir && $nodir ]] && echo "*** Error: --create-dir and --no-dir options are mutually exclusive." - - [[ ! $LIST ]] && local LIST="." - - for zitem in $LIST; do - [[ $(ls $zitem/*.zip 2> /dev/null | wc -l) -eq 0 ]] && - echo "$zitem contains no supported archive file, skipping." && - continue - - for f in $zitem/*.zip; do - echo -n "Processing archive $zitem/$f... " - local dir=${f::-4} - - mkdir -p $dir - [[ $? -gt 0 ]] && - echo "[ filesystem can't create directories, exit ]" && - return 1 - - unzip -o $f -d $dir > /dev/null 2>&1 - case $? in - 0) - [[ $willrm ]] && rm -f $f && echo -n "Deleted ! " - ;; - - 1) - echo "No deletion on warnings " - ;; - *) - echo "[ zip file corrupted, failed ]" - rm -rf $dir > /dev/null 2>&1 - continue - ;; - esac - - if [[ $createdir ]]; then - echo -n "[ subdir created, " - elif [[ $nodir ]]; then - mv ./$dir/* ./ && rmdir $dir - echo -n "[ No subdir, " - else - subdirs=$(find $dir -maxdepth 1 | wc -l) - if [[ $subdirs -eq 2 ]]; then - mv ./$dir/* ./ && rmdir $dir - echo -n "[ No subdir, " - else - echo -n "[ subdir created, " - fi - fi - echo " OK ]" - done - done -} -export -f utaz - -# ------------------------------------------------------------------------------ -# Compress directories or files into one or more archive -# ------------------------------------------------------------------------------ -taz () -{ - _doxz() - { - command -v xz >/dev/null 2>&1 || { - echo -e >&2 "\t*** The program 'xz' is not installed, aborting." - return 127 - } - - [[ $4 ]] && local verb='-v' - - # Display a warning for this format - echo -e "\t! Warning: xz format is not suited for long term archiving." - echo -e "\t See https://www.nongnu.org/lzip/xz_inadequate.html for details." - - # Compresse to xz (lzma2) - Deprecated - xz $verb --compress --keep -$3 -T $2 $1 - return $? - } - - _dolz() - { - local procopt="--threads $2" - local command=plzip - - command -v plzip >/dev/null 2>&1 || { - command -v lzip >/dev/null 2>&1 || { - echo -e >&2 "\t*** Program 'plzip' or 'lzip' are not installed, aborting." - return 127 - } - local command=lzip - local procopt="" - [[ $2 -gt 1 ]] && - echo -e "\t! Warning: lzip doesn't support multithreading, falling back to 1 thread." && - echo -e "\t* Consitder installing plzip to obtain multithreading abilities." - } - - [[ $4 ]] && local verb="-vv" - - # Compresse au format lzip (lzma) - $command $verb $procopt --keep -$3 $1 - return $? - } - - _dogz() - { - local procopt="--processes $2" - local command=pigz - - command -v pigz >/dev/null 2>&1 || { - command -v gzip >/dev/null 2>&1 || { - echo -e >&2 "\t*** Programs 'pigz' or 'gzip' are not installed, aborting." - return 127 - } - local command="gzip --compress" - local procopt="" - [[ $2 -gt 1 ]] && - echo -e "\t! Warning: gzip doesn't support multithreading, falling back to 1 thread." && - echo -e "\t* Consitder installing pigz to obtain multithreading abilities." - } - - [[ $4 ]] && local verb="--verbose" - - # Compresse au format bz2 - $command $verb $procopt --keep -$3 $1 - return $? - } - - _dobz2() - { - local procopt="-p$2" - local command=pbzip2 - - command -v pbzip2 >/dev/null 2>&1 || { - command -v bzip2 >/dev/null 2>&1 || { - echo -e >&2 "\t*** The program 'pbzip2' or 'bzip2' are not installed, aborting." - return 127 - } - local command=bzip2 - local procopt="" - [[ $2 -gt 1 ]] && - echo -e "\t! Warning: bzip2 doesn't support multithreading, falling back to 1 thread." && - echo -e "\t* Consitder installing pbzip2 to obtain multithreading abilities." - } - - [[ $4 ]] && local verb="-v" - - # Compresse au format bz2 - $command $verb --compress $procopt --keep -$3 $1 - return $? - } - - _dolzo() - { - command -v lzop >/dev/null 2>&1 || { - echo -e >&2 "\t*** The program 'lzop' is not installed, aborting." - return 127 - } - - [[ $4 ]] && local verb='-v' - [[ $2 -gt 1 ]] && echo -e "\t! Warning: lzop doesn't support multithreading, falling back to 1 thread." - - # Compresse au format lzo - lzop --keep -$3 $1 - 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 " -1, .., -9 Compression level to use [1=fast/big, 9=slow/small]" - 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 - return 0 - ;; - - "-d"|"--delete") - local willrm=1 - ;; - - "-f"?*|"--format"?*) - local compform=$(echo "$opt" | cut -f 2- -d '=') - ;; - - "-p"?*|"--parallel"?*) - local nproc=$(echo "$opt" | cut -f 2- -d '=') - ;; - - "-v"|"--verbose") - local verbose=1 - ;; - - "-"[1..9]) - local complevel=${opt:1:1} - ;; - - "-"*) - echo "Invalid option, use taz --help to display options list" - echo - return 1 - ;; - - *) - local LIST="$LIST ${opt%/}" - ;; - esac - done - - [[ ! $compform ]] && compform=lz # safe and efficient (unless data are already compressed) - [[ ! $nproc ]] && nproc=1 - [[ ! $complevel ]] && complevel=6 - - for item in $LIST; do - local donetar=0 - echo "--- Processing $item..." - - if [[ -d $item ]]; then - echo -ne "\t* Creating $item.tar... " - - tar -cf $item{.tar,} - if [[ ! $? -eq 0 ]]; then - echo "[ failed, skipping ]" - continue - fi - - local donetar=1 - echo "[ OK ]" - fi - - local fname=$item - [[ $donetar -gt 0 ]] && fname=$item.tar - - # Skip compression part if tar is asked - if [[ $compform != "tar" ]]; then - echo -e "\t* Compressing archive..." - _do$compform $fname $nproc $complevel $verbose - [[ ! $? -eq 0 ]] && case $? in - 127) - echo -e "\t*** Compression program unavailable, aborting." - return 127 - ;; - *) - echo -e "\t*** Compression program returned an error, not deleting anything if asked, skipping to next item." - continue - ;; - esac - - [[ $donetar -gt 0 ]] && rm $fname - fi - - if [[ $willrm ]]; then - echo -en "\t* Deleting original source as asked... " - rm -r $item && echo '[ OK ]' || echo '[ failed ]' - fi - - echo "--- Done" - done - -} -export -f taz - -# ------------------------------------------------------------------------------ -# Display system general information -# ------------------------------------------------------------------------------ -showinfo() -{ - echo -e "\n" - if command -v figlet >/dev/null 2>&1; then - figlet -k $(hostname) - else - echo "$(hostname -f)" - fi - echo "" - if command -v neofetch >/dev/null 2>&1; then - neofetch - else - ( - if [[ -s /etc/os-release ]]; then - . /etc/os-release - echo "$NAME $VERSION" - else - cat /proc/version - fi - echo "Uptime: $(uptime)" - ) - fi -} -export -f showinfo - - -# ------------------------------------------------------------------------------ -# Let the rain fall -# ------------------------------------------------------------------------------ -rain() -{ - local EXIT_ST=0 - local RAINS=("|" "│" "┃" "┆" "┇" "┊" "┋" "╽" "╿") - local COLORS=("\e[37m" "\e[37;1m") - # More from 256 color mode - for i in {244..255}; do - COLORS=( "${COLORS[@]}" "\e[38;5;${i}m" ) - done - local NRAINS=${#RAINS[@]} - local NCOLORS=${#COLORS[@]} - local NUM_RAIN_METADATA=5 - local TERM_HEIGHT=$(tput lines) - local TERM_WIDTH=$(tput cols) - local STEP_DURATION=0.025 - local X=0 Y=0 LENTH=0 RAIN=0 MAX_RAINS=0 NEW_RAIN_ODD=0 FALLING_ODD=0 - - - sigwinch() { - TERM_WIDTH=$(tput cols) - TERM_HEIGHT=$(tput lines) - STEP_DURATION=0.025 - (( MAX_RAINS = TERM_WIDTH * TERM_HEIGHT / 4 )) - (( MAX_RAIN_LENGTH = TERM_HEIGHT < 10 ? 1 : TERM_HEIGHT / 10 )) - # In percentage - (( NEW_RAIN_ODD = TERM_HEIGHT > 50 ? 100 : TERM_HEIGHT * 2 )) - (( NEW_RAIN_ODD = NEW_RAIN_ODD * 75 / 100 )) - (( FALLING_ODD = TERM_HEIGHT > 25 ? 100 : TERM_HEIGHT * 4 )) - (( FALLING_ODD = FALLING_ODD * 90 / 100 )) - } - - do_exit() { - EXIT_ST=1 - } - - do_render() { - # Clean screen first - local idx=0 - for ((idx = 0; idx < num_rains * NUM_RAIN_METADATA; idx += NUM_RAIN_METADATA)); do - X=${rains[idx]} - Y=${rains[idx + 1]} - LENGTH=${rains[idx + 4]} - for ((y = Y; y < Y + LENGTH; y++)); do - (( y < 1 || y > TERM_HEIGHT )) && continue - echo -ne "\e[${y};${X}H " - done - done - - for ((idx = 0; idx < num_rains * NUM_RAIN_METADATA; idx += NUM_RAIN_METADATA)); do - if (( 100 * RANDOM / 32768 < FALLING_ODD )); then - # Falling - if (( ++rains[idx + 1] > TERM_HEIGHT )); then - # Out of screen, bye sweet <3 - rains=("${rains[@]:0:idx}" - "${rains[@]:idx+NUM_RAIN_METADATA:num_rains*NUM_RAIN_METADATA}") - (( num_rains-- )) - continue - fi - fi - X=${rains[idx]} - Y=${rains[idx + 1]} - RAIN=${rains[idx + 2]} - COLOR=${rains[idx + 3]} - LENGTH=${rains[idx + 4]} - for ((y = Y; y < Y + LENGTH; y++)); do - (( y < 1 || y > TERM_HEIGHT )) && continue - echo -ne "\e[${y};${X}H${COLOR}${RAIN}" - done - done - } - - trap do_exit TERM INT - trap sigwinch WINCH - # No echo stdin and hide the cursor - stty -echo - echo -ne "\e[?25l" - - echo -ne "\e[2J" - local rains=() - local num_rains=0 - sigwinch - while (( EXIT_ST <= 0 )); do - if (( $EXIT_ST <=0 )); then - read -n 1 -t $STEP_DURATION ch - case "$ch" in - q|Q) - do_exit - ;; - esac - - if (( num_rains < MAX_RAINS )) && (( 100 * RANDOM / 32768 < NEW_RAIN_ODD )); then - # Need new |, 1-based - RAIN="${RAINS[NRAINS * RANDOM / 32768]}" - COLOR="${COLORS[NCOLORS * RANDOM / 32768]}" - LENGTH=$(( MAX_RAIN_LENGTH * RANDOM / 32768 + 1 )) - X=$(( TERM_WIDTH * RANDOM / 32768 + 1 )) - Y=$(( 1 - LENGTH )) - rains=( "${rains[@]}" "$X" "$Y" "$RAIN" "$COLOR" "$LENGTH" ) - (( num_rains++ )) - fi - - # Let rain fall! - do_render - fi - done - echo -ne "\e[${TERM_HEIGHT};1H\e[0K" - - # Show cursor and echo stdin - echo -ne "\e[?25h" - stty echo - unset EXIT_ST - trap - TERM INT - trap - WINCH -} -export -f rain - - -# ------------------------------------------------------------------------------ -# Display list of commands and general informations -# ------------------------------------------------------------------------------ -help () -{ - cat <