#!/usr/bin/env bash # ------------------------------------------------------------------------------ # Copyright (c) 2013-2022 Geoffray Levasseur # Protected by the BSD3 license. Please read bellow for details. # # * Redistribution and use in source and binary forms, # * with or without modification, are permitted provided # * that the following conditions are met: # * # * Redistributions of source code must retain the above # * copyright notice, this list of conditions and the # * following disclaimer. # * # * Redistributions in binary form must reproduce the above # * copyright notice, this list of conditions and the following # * disclaimer in the documentation and/or other materials # * provided with the distribution. # * # * Neither the name of the copyright holder nor the names # * of any other contributors may be used to endorse or # * promote products derived from this software without # * specific prior written permission. # * # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND # * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR # * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # * OF SUCH DAMAGE. # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # 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 ;; "-"*) disp E "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 disp E "Create a directory then goes inside." disp E "Usage: mcd " return 1 fi mkdir -pv "$1" && cd "$1" || echo "Failed create or change directory." } 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 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 ;; "-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 ;; esac done [[ ! $substchar ]] && substchar="_" [[ $substchar == "none" ]] && local substchar="" [[ $verb ]] && local mvopt="-v" for f in *; do [[ $recurs ]] && [[ -d "$f" ]] && ( [[ $verb ]] && disp I "Entering directory $(pwd)/$f ..." local lastdir=$f pushd "$f" >/dev/null rmspc $@ popd >/dev/null [[ $verb ]] && disp I "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 # ------------------------------------------------------------------------------ # Rename all files in current directory to replace spaces with _ # ------------------------------------------------------------------------------ file_stats() { 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 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 ;; esac shift done [ -n "$1" ] && path="$1" # Prepare find filters local find_cmd=(find "$path" -type f) # Extension simple if [[ -n "$ext_filter" ]]; then find_cmd+=(-iname "*.$ext_filter") fi # Extension liste if [[ -n "$ext_list" ]]; then IFS=',' read -ra exts <<< "$ext_list" find_cmd+=('(') for i in "${!exts[@]}"; do [[ $i -ne 0 ]] && find_cmd+=(-o) find_cmd+=(-iname "*.${exts[$i]}") done find_cmd+=(')') fi # Taille min/max (à évaluer en octets) if [[ -n "$min_size" ]]; then find_cmd+=(-size +"$(numfmt --from=iec "$min_size")"c) fi if [[ -n "$max_size" ]]; then find_cmd+=(-size -"$(( $(numfmt --from=iec "$max_size") + 1 ))"c) 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" ' function human_readable(x) { split("B KiB MiB GiB TiB", units) for (i=1; x>=1024 && i<5; i++) x /= 1024 return sprintf("%.2f %s", x, units[i]) } { sizes[NR] = $1 total += $1 if (min == "" || $1 < min) min = $1 if (max == "" || $1 > max) max = $1 if ($1 == 0) bucket[0]++ else { b = int(log($1)/log(1024)) bucket[b]++ } } END { count = NR if (count == 0) { print "Aucun fichier trouvé."; exit } moyenne = total / count if (count % 2 == 1) mediane = sizes[(count + 1) / 2] else mediane = (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) else { if (show_all || human || details) { printf "Statistiques sur \"%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) } 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] } } }' } # ------------------------------------------------------------------------------ # EOF