huge longrun improvements
This commit is contained in:
@@ -36,9 +36,17 @@
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# expandlist : treat wildcards in a file/directory list
|
||||
# ------------------------------------------------------------------------------
|
||||
# Usage: expandlist <item1 [item2 ... itemN]>
|
||||
expandlist()
|
||||
{
|
||||
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
|
||||
printf "expandlist: Wraps a list of items in double quotes.\n\n"
|
||||
printf "Usage: expandlist <item1 [item2 ... itemN]>\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 <directory>
|
||||
mcd()
|
||||
{
|
||||
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
|
||||
printf "mcd: Create a directory and enter it.\n\n"
|
||||
printf "Usage: mcd <directory>\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 <directory>"
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user