improved and modernised file functions
This commit is contained in:
@@ -35,32 +35,85 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# expandlist : treat wildcards in a file/directory list
|
||||
# Usage: expandlist <item1 [item2 ... itemN]>
|
||||
# Expand wildcards in a file/directory list and quote the results
|
||||
# Usage: expandlist [options] <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"
|
||||
local separator=" "
|
||||
local PARSED
|
||||
|
||||
PARSED=$(getopt -o hs:n --long help,separator:,newline -n 'expandlist' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"expandlist --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
printf "expandlist: expand globs and wrap matched items in double quotes.\n\n"
|
||||
printf "Usage: expandlist [options] <item1 [item2 ... itemN]>\n\n"
|
||||
printf "Options:\n"
|
||||
printf "\t-h, --help\t\tDisplay this help screen\n"
|
||||
printf "\t-s, --separator SEP\tSet output separator (default: space)\n"
|
||||
printf "\t-n, --newline\t\tUse a newline as separator\n"
|
||||
return 0
|
||||
;;
|
||||
-s|--separator)
|
||||
separator="$2"
|
||||
shift 2
|
||||
;;
|
||||
-n|--newline)
|
||||
separator=$'\n'
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
disp E "Invalid options, use \"expandlist --help\" to display usage."
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
local item="" result="" matched=0
|
||||
shopt -s nullglob
|
||||
|
||||
for item in "$@"; do
|
||||
local expanded=()
|
||||
|
||||
# True glob expansion when wildcards are present.
|
||||
if [[ "$item" == *'*'* || "$item" == *'?'* || "$item" == *'['* ]]; then
|
||||
expanded=( $item )
|
||||
else
|
||||
expanded=( "$item" )
|
||||
fi
|
||||
|
||||
local result=""
|
||||
for item in "$@"; do
|
||||
for content in "$item"; do
|
||||
result+="\"$content\" "
|
||||
if [[ ${#expanded[@]} -eq 0 ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
for content in "${expanded[@]}"; do
|
||||
if (( matched )); then
|
||||
result+="$separator"
|
||||
fi
|
||||
result+="\"$content\""
|
||||
matched=1
|
||||
done
|
||||
done
|
||||
echo $result
|
||||
|
||||
shopt -u nullglob
|
||||
printf '%s\n' "$result"
|
||||
}
|
||||
export -f expandlist
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Clean a directory or a tree from temporary or backup files
|
||||
# Clean a directory tree from temporary or backup files
|
||||
# Usage: clean [options] [directory1] [...[directoryX]]
|
||||
# Options:
|
||||
# -h, --help: display help screen
|
||||
@@ -85,7 +138,7 @@ clean()
|
||||
while true; do
|
||||
case "$1" in
|
||||
-r|--recurs)
|
||||
local recursive=1
|
||||
recursive=1
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
@@ -100,11 +153,11 @@ clean()
|
||||
return 0
|
||||
;;
|
||||
-s|--shell)
|
||||
local outshell=1
|
||||
outshell=1
|
||||
shift
|
||||
;;
|
||||
-f|--force)
|
||||
local force=1
|
||||
force=1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
@@ -114,6 +167,7 @@ clean()
|
||||
*)
|
||||
disp E "Invalid parameter, use \"clean --help\" to display options list"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -121,21 +175,24 @@ clean()
|
||||
local dirlist=("$@")
|
||||
[[ ${#dirlist[@]} -eq 0 ]] && dirlist=(".")
|
||||
|
||||
local findopt=() rmopt
|
||||
[[ ! $recursive ]] && findopt=(-maxdepth 1)
|
||||
[[ ! $force ]] && rmopt="-i"
|
||||
unset recursive force
|
||||
local findopt=() rmopt=()
|
||||
(( ! recursive )) && findopt=(-maxdepth 1)
|
||||
(( ! force )) && rmopt=(-i)
|
||||
|
||||
for dir in $dirlist; 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
|
||||
for dir in "${dirlist[@]}"; 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
|
||||
if (( ${#rmopt[@]} )); then
|
||||
printf 'rm %s -- "%s"\n' "${rmopt[*]}" "$f"
|
||||
else
|
||||
echo "rm $rmopt $f"
|
||||
printf 'rm -- "%s"\n' "$f"
|
||||
fi
|
||||
else
|
||||
rm "${rmopt[@]}" -- "$f"
|
||||
fi
|
||||
done
|
||||
done
|
||||
unset outshell dirlist dellist findopt rmopt
|
||||
}
|
||||
export -f clean
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -168,7 +225,7 @@ export -f mcd
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Rename all files in current directory to replace spaces with _
|
||||
# Rename files and directories to replace spaces with another character
|
||||
# Usage: rmspc [options]
|
||||
# Options:
|
||||
# -h, --help: display help screen
|
||||
@@ -178,8 +235,11 @@ export -f mcd
|
||||
# -s, --shell: do nothing and display commands that would be executed
|
||||
rmspc()
|
||||
{
|
||||
local lst=""
|
||||
local recurs=0 verb=0 shell=0
|
||||
local substchar="_" substchar_set=0
|
||||
local mvopt=()
|
||||
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."
|
||||
@@ -203,27 +263,20 @@ rmspc()
|
||||
return 0
|
||||
;;
|
||||
-r|--recursive)
|
||||
local recurs=1
|
||||
recurs=1
|
||||
shift
|
||||
;;
|
||||
-c|--subst-char)
|
||||
# Handle optional argument for short/long options
|
||||
case "$2" in
|
||||
"")
|
||||
substchar=""
|
||||
;;
|
||||
*)
|
||||
substchar_set=1
|
||||
substchar="$2"
|
||||
;;
|
||||
esac
|
||||
shift 2
|
||||
;;
|
||||
-v|--verbose)
|
||||
local verb=1
|
||||
verb=1
|
||||
shift
|
||||
;;
|
||||
-s|--shell)
|
||||
local shell=1
|
||||
shell=1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
@@ -232,49 +285,58 @@ rmspc()
|
||||
;;
|
||||
*)
|
||||
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"
|
||||
[[ "$substchar" == "none" ]] && substchar=""
|
||||
(( verb )) && mvopt=(-v)
|
||||
|
||||
shopt -s nullglob
|
||||
for f in *; do
|
||||
[[ $recurs ]] && [[ -d "$f" ]] && (
|
||||
[[ $verb ]] && disp I "Entering directory $(pwd)/$f ..."
|
||||
if (( recurs )) && [[ -d "$f" ]]; then
|
||||
(
|
||||
local lastdir=$f
|
||||
pushd "$f" >/dev/null
|
||||
rmspc ${recurs:+-r} ${substchar:+-c "$substchar"} ${verb:+-v} ${shell:+-s}
|
||||
popd >/dev/null
|
||||
[[ $verb ]] && disp I "Leaving directory $(pwd)/$lastdir"
|
||||
unset lastdir
|
||||
(( verb )) && disp I "Entering directory $(pwd)/$f ..."
|
||||
pushd "$f" >/dev/null || exit 1
|
||||
|
||||
if (( substchar_set )); then
|
||||
rmspc ${recurs:+-r} -c "$substchar" ${verb:+-v} ${shell:+-s}
|
||||
else
|
||||
rmspc ${recurs:+-r} ${verb:+-v} ${shell:+-s}
|
||||
fi
|
||||
|
||||
popd >/dev/null || exit 1
|
||||
(( verb )) && disp I "Leaving directory $(pwd)/$lastdir"
|
||||
)
|
||||
fi
|
||||
|
||||
if [[ "$f" == *" "* ]]; then
|
||||
local newf="${f// /${substchar}}"
|
||||
[[ "$f" == "$newf" ]] && continue # protection but should never happen
|
||||
if [[ -n $shell ]]; then
|
||||
echo "mv ${mvopt:+$mvopt }\"$f\" \"$newf\""
|
||||
[[ "$f" == "$newf" ]] && continue
|
||||
if (( shell )); then
|
||||
if (( ${#mvopt[@]} )); then
|
||||
printf 'mv %s -- "%s" "%s"\n' "${mvopt[*]}" "$f" "$newf"
|
||||
else
|
||||
mv ${mvopt:+$mvopt} "$f" "$newf" || {
|
||||
printf 'mv -- "%s" "%s"\n' "$f" "$newf"
|
||||
fi
|
||||
else
|
||||
mv "${mvopt[@]}" -- "$f" "$newf" || {
|
||||
disp E "Failed renaming \"$f\" to \"$newf\"."
|
||||
continue
|
||||
}
|
||||
fi
|
||||
fi
|
||||
done
|
||||
unset lst substchar verb shell newf command mvopt
|
||||
shopt -u nullglob
|
||||
}
|
||||
export -f rmspc
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# display stats about a file structure
|
||||
# Display statistics about a file tree
|
||||
# Usage: file_stats [options] [path]
|
||||
# Options:
|
||||
# -H, --human Human readable sizes\n"
|
||||
@@ -290,7 +352,7 @@ export -f rmspc
|
||||
# --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 PARSED
|
||||
@@ -387,12 +449,12 @@ local human=0 details=0 only_avg=0 only_med=0 only_count=0 only_total=0
|
||||
# Prepare find filters
|
||||
local find_cmd=(find "$path" -type f)
|
||||
|
||||
# Extension simple
|
||||
# Single extension filter
|
||||
if [[ -n "$ext_filter" ]]; then
|
||||
find_cmd+=(-iname "*.$ext_filter")
|
||||
fi
|
||||
|
||||
# Extension liste
|
||||
# Extension list filter
|
||||
if [[ -n "$ext_list" ]]; then
|
||||
IFS=',' read -ra exts <<< "$ext_list"
|
||||
find_cmd+=('(')
|
||||
@@ -403,7 +465,7 @@ local human=0 details=0 only_avg=0 only_med=0 only_count=0 only_total=0
|
||||
find_cmd+=(')')
|
||||
fi
|
||||
|
||||
# Taille min/max (à évaluer en octets)
|
||||
# Minimum/maximum size filters (evaluated in bytes)
|
||||
if [[ -n "$min_size" ]]; then
|
||||
find_cmd+=(-size +"$(numfmt --from=iec "$min_size")"c)
|
||||
fi
|
||||
@@ -411,7 +473,7 @@ local human=0 details=0 only_avg=0 only_med=0 only_count=0 only_total=0
|
||||
find_cmd+=(-size -"$(( $(numfmt --from=iec "$max_size") + 1 ))"c)
|
||||
fi
|
||||
|
||||
# Exécution
|
||||
# Execution
|
||||
"${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" \
|
||||
@@ -512,10 +574,10 @@ export -f file_stats
|
||||
# -l : limit : number of files to return (default is 10)
|
||||
findbig()
|
||||
{
|
||||
local details=0 limit=10 no_change=0 one_fs=0
|
||||
local details=0 limit=10 one_fs=0
|
||||
|
||||
local PARSED
|
||||
PARSED=$(getopt -o hd:l:x --long help,details,one-fs,limit: -n 'findbig' -- "$@")
|
||||
PARSED=$(getopt -o hdl:x --long help,details,limit:,one-fs -n 'findbig' -- "$@")
|
||||
if [[ $? -ne 0 ]]; then
|
||||
disp E "Invalid options, use \"findbig --help\" to display usage."
|
||||
return 1
|
||||
@@ -538,14 +600,18 @@ findbig()
|
||||
details=1
|
||||
shift
|
||||
;;
|
||||
-n|--no-change)
|
||||
no_change=1
|
||||
shift
|
||||
;;
|
||||
-l|--limit)
|
||||
limit="$2"
|
||||
[[ "$limit" =~ ^[0-9]+$ ]] || {
|
||||
disp E "Invalid limit: must be a positive integer."
|
||||
return 1
|
||||
}
|
||||
shift 2
|
||||
;;
|
||||
-x|--one-fs)
|
||||
one_fs=1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
@@ -560,13 +626,16 @@ findbig()
|
||||
local dir="${1:-.}"
|
||||
|
||||
# Prepare find arguments in an array for cleaner handling
|
||||
local find_args=("-L" "$dir" "-type" "f")
|
||||
(( one_fs )) && find_args+=("-xdev")
|
||||
local find_args=(-L "$dir")
|
||||
(( one_fs )) && find_args+=(-xdev)
|
||||
find_args+=(-type f)
|
||||
|
||||
# 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"
|
||||
find "${find_args[@]}" -printf "%s %p\n" 2>/dev/null | sort -rn | head -n "$limit" |
|
||||
while IFS= read -r line; do
|
||||
local path="${line#* }"
|
||||
ls -ld -- "$path"
|
||||
done
|
||||
else
|
||||
find "${find_args[@]}" -printf "%s %p\n" 2>/dev/null | sort -rn | head -n "$limit"
|
||||
@@ -586,7 +655,7 @@ export -f findbig
|
||||
# --delete : delete empty files and display their paths
|
||||
findzero()
|
||||
{
|
||||
local delete=0 details=0 one_fs=0 no_change=0
|
||||
local delete=0 details=0 one_fs=0
|
||||
|
||||
local PARSED
|
||||
# o: options, long: long equivalents
|
||||
@@ -660,7 +729,7 @@ export -f findzero
|
||||
# --delete : delete dead links and display their paths
|
||||
finddead()
|
||||
{
|
||||
local delete=0 details=0 one_fs=0 no_change=0
|
||||
local delete=0 details=0 one_fs=0
|
||||
|
||||
local PARSED
|
||||
PARSED=$(getopt -o hdx --long help,details,one-fs,delete -n 'finddead' -- "$@")
|
||||
|
||||
Reference in New Issue
Block a user