filefct bug fix
This commit is contained in:
+171
-69
@@ -37,7 +37,9 @@
|
||||
load_conf "filefct"
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Expand wildcards in a file/directory list and quote the results
|
||||
# Expand wildcards in a file/directory list and quote the results: each match is
|
||||
# wrapped in double quotes (with \, ", $ and ` escaped) and the matches are
|
||||
# joined with the separator. Items without wildcards are quoted as they are.
|
||||
# Usage: expandlist [options] <item1 [item2 ... itemN]>
|
||||
expandlist()
|
||||
{
|
||||
@@ -49,9 +51,8 @@ expandlist()
|
||||
disp E "Invalid options, use \"expandlist --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
local -a _pargs=()
|
||||
readarray -td '' _pargs < <(printf '%s' "$PARSED" | xargs printf '%s\0')
|
||||
set -- "${_pargs[@]}"
|
||||
# Restore the getopt-normalised (shell-quoted) argument list
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
@@ -60,7 +61,7 @@ expandlist()
|
||||
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-s, --separator SEP\tSet output separator (default: space); \\\\n, \\\\t... are interpreted\n"
|
||||
printf "\t-n, --newline\t\tUse a newline as separator\n"
|
||||
return 0
|
||||
;;
|
||||
@@ -83,15 +84,25 @@ expandlist()
|
||||
esac
|
||||
done
|
||||
|
||||
# Backslash escapes in the separator (\n, \t, ...) are interpreted, so the
|
||||
# configuration file can express a newline as EXPANDLIST_DEFAULT_SEPARATOR=\n
|
||||
printf -v separator '%b' "$separator"
|
||||
|
||||
local item="" result="" matched=0
|
||||
# Restore the caller's nullglob setting on exit instead of forcing it off.
|
||||
local _saved_nullglob
|
||||
_saved_nullglob=$(shopt -p nullglob)
|
||||
shopt -s nullglob
|
||||
# An empty IFS keeps the unquoted expansion below from splitting on spaces
|
||||
# (it would cut "my dir/*.txt" in two) while globbing still happens.
|
||||
local IFS=
|
||||
|
||||
for item in "$@"; do
|
||||
local expanded=()
|
||||
|
||||
# True glob expansion when wildcards are present.
|
||||
if [[ "$item" == *'*'* || "$item" == *'?'* || "$item" == *'['* ]]; then
|
||||
# shellcheck disable=SC2206 # We actually want the word splitting
|
||||
# shellcheck disable=SC2206 # Intentional glob expansion, no splitting (IFS is empty)
|
||||
expanded=( $item )
|
||||
else
|
||||
expanded=( "$item" )
|
||||
@@ -106,13 +117,19 @@ expandlist()
|
||||
if (( matched )); then
|
||||
result+="$separator"
|
||||
fi
|
||||
# Escape what stays special inside double quotes so that the output
|
||||
# can safely be re-evaluated (eval, command substitution, ...).
|
||||
content=${content//\\/\\\\}
|
||||
content=${content//\"/\\\"}
|
||||
content=${content//\$/\\\$}
|
||||
content=${content//\`/\\\`}
|
||||
result+="\"$content\""
|
||||
matched=1
|
||||
done
|
||||
unset content
|
||||
done
|
||||
|
||||
shopt -u nullglob
|
||||
eval "$_saved_nullglob"
|
||||
printf '%s\n' "$result"
|
||||
}
|
||||
export -f expandlist
|
||||
@@ -140,9 +157,8 @@ clean()
|
||||
return 1
|
||||
fi
|
||||
|
||||
local -a _pargs=()
|
||||
readarray -td '' _pargs < <(printf '%s' "$PARSED" | xargs printf '%s\0')
|
||||
set -- "${_pargs[@]}"
|
||||
# Restore the getopt-normalised (shell-quoted) argument list
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
@@ -190,13 +206,17 @@ clean()
|
||||
|
||||
local dir f
|
||||
for dir in "${dirlist[@]}"; do
|
||||
find "$dir" "${findopt[@]}" -type f \( -name "*~" -o -name "#*#" -o -name "*.bak" -o -name ".~*#" \) -print0 |
|
||||
# "./" keeps a name starting with "-" from being read as a find option.
|
||||
# -H follows a symlink given as argument (a link to a directory).
|
||||
[[ $dir == -* ]] && dir="./$dir"
|
||||
find -H "$dir" "${findopt[@]}" -type f \( -name "*~" -o -name "#*#" -o -name "*.bak" -o -name ".~*#" \) -print0 |
|
||||
while IFS= read -r -d '' f; do
|
||||
if (( outshell )); then
|
||||
# %q prints a re-usable (shell-quoted) form of the name
|
||||
if (( ${#rmopt[@]} )); then
|
||||
printf 'rm %s -- "%s"\n' "${rmopt[*]}" "$f"
|
||||
printf 'rm %s -- %q\n' "${rmopt[*]}" "$f"
|
||||
else
|
||||
printf 'rm -- "%s"\n' "$f"
|
||||
printf 'rm -- %q\n' "$f"
|
||||
fi
|
||||
elif (( force )); then
|
||||
# No confirmation: rm reads no stdin, so leave it attached
|
||||
@@ -233,11 +253,11 @@ mcd()
|
||||
disp E "Missing parameter. Use \"mcd --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
if ! mkdir -pv "$1"; then
|
||||
if ! mkdir -pv -- "$1"; then
|
||||
disp E "Failed to create directory \"$1\"."
|
||||
return 1
|
||||
fi
|
||||
if ! cd "$1"; then
|
||||
if ! cd -- "$1"; then
|
||||
disp E "Failed to change to directory \"$1\"."
|
||||
return 1
|
||||
fi
|
||||
@@ -268,9 +288,8 @@ rmspc()
|
||||
disp E "Invalid options, use \"rmspc --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
local -a _pargs=()
|
||||
readarray -td '' _pargs < <(printf '%s' "$PARSED" | xargs printf '%s\0')
|
||||
set -- "${_pargs[@]}"
|
||||
# Restore the getopt-normalised (shell-quoted) argument list
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
@@ -280,11 +299,12 @@ rmspc()
|
||||
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-c, --subst-char[=C]\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"
|
||||
printf "Note: the character must be attached (-c- or --subst-char=-). If the option\n"
|
||||
printf " is given without a character, spaces are replaced with nothing\n"
|
||||
printf " (concatenation). An existing file is never overwritten.\n"
|
||||
return 0
|
||||
;;
|
||||
-r|--recursive)
|
||||
@@ -315,16 +335,36 @@ rmspc()
|
||||
esac
|
||||
done
|
||||
|
||||
# getopt only attaches an optional argument written as -cX or --subst-char=X;
|
||||
# "-c X" leaves X behind as a positional argument, which rmspc does not take
|
||||
# (it works on the current directory) and would otherwise silently ignore.
|
||||
if [[ $# -gt 0 ]]; then
|
||||
disp E "Unexpected argument '$1'. The replacement character must be attached: -c$1 or --subst-char=$1"
|
||||
return 1
|
||||
fi
|
||||
|
||||
[[ "$substchar" == "none" ]] && substchar=""
|
||||
# A slash would turn the new name into a path
|
||||
if [[ "$substchar" == */* ]]; then
|
||||
disp E "The replacement character must not contain a slash."
|
||||
return 1
|
||||
fi
|
||||
(( verb )) && mvopt=(-v)
|
||||
|
||||
# Restore the caller's nullglob setting on exit instead of forcing it off.
|
||||
local _saved_nullglob
|
||||
_saved_nullglob=$(shopt -p nullglob)
|
||||
shopt -s nullglob
|
||||
local f
|
||||
for f in *; do
|
||||
if (( recurs )) && [[ -d "$f" ]]; then
|
||||
# Symlinks to directories are not followed (no escape from the tree,
|
||||
# no loops).
|
||||
if (( recurs )) && [[ -d "$f" && ! -L "$f" ]]; then
|
||||
(
|
||||
local lastdir=$f
|
||||
(( verb )) && disp I "Entering directory $(pwd)/$f ..."
|
||||
if (( verb )); then
|
||||
disp I "Entering directory $(pwd)/$f ..."
|
||||
fi
|
||||
pushd "$f" >/dev/null || return 1
|
||||
|
||||
# Build the recursive argument list by value: the ${var:+-flag}
|
||||
@@ -333,25 +373,36 @@ rmspc()
|
||||
local rargs=(-r)
|
||||
(( verb )) && rargs+=(-v)
|
||||
(( shell )) && rargs+=(-s)
|
||||
(( substchar_set )) && rargs+=(-c "$substchar")
|
||||
# Attached form, mandatory for an optional argument (see above)
|
||||
(( substchar_set )) && rargs+=(--subst-char="$substchar")
|
||||
rmspc "${rargs[@]}"
|
||||
|
||||
popd >/dev/null || return 1
|
||||
(( verb )) && disp I "Leaving directory $(pwd)/$lastdir"
|
||||
# "if" rather than "(( verb )) && ...": the subshell status is
|
||||
# that of its last command and must stay 0 when verb is off.
|
||||
if (( verb )); then
|
||||
disp I "Leaving directory $(pwd)/$lastdir"
|
||||
fi
|
||||
)
|
||||
fi
|
||||
|
||||
if [[ "$f" == *" "* ]]; then
|
||||
local newf="${f// /${substchar}}"
|
||||
# Quoted replacement: an unquoted "&" would stand for the match
|
||||
local newf="${f// /"$substchar"}"
|
||||
[[ "$f" == "$newf" ]] && continue
|
||||
# Never overwrite (mv would silently replace an existing file)
|
||||
if [[ -e "$newf" || -L "$newf" ]]; then
|
||||
disp E "Cannot rename \"$f\": \"$newf\" already exists."
|
||||
continue
|
||||
fi
|
||||
if (( shell )); then
|
||||
if (( ${#mvopt[@]} )); then
|
||||
printf 'mv %s -- "%s" "%s"\n' "${mvopt[*]}" "$f" "$newf"
|
||||
printf 'mv %s -- %q %q\n' "${mvopt[*]}" "$f" "$newf"
|
||||
else
|
||||
printf 'mv -- "%s" "%s"\n' "$f" "$newf"
|
||||
printf 'mv -- %q %q\n' "$f" "$newf"
|
||||
fi
|
||||
else
|
||||
mv "${mvopt[@]}" -- "$f" "$newf" || {
|
||||
mv -n "${mvopt[@]}" -- "$f" "$newf" || {
|
||||
disp E "Failed renaming \"$f\" to \"$newf\"."
|
||||
continue
|
||||
}
|
||||
@@ -359,7 +410,7 @@ rmspc()
|
||||
fi
|
||||
done
|
||||
unset f
|
||||
shopt -u nullglob
|
||||
eval "$_saved_nullglob"
|
||||
}
|
||||
export -f rmspc
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -369,7 +420,7 @@ export -f rmspc
|
||||
# Display statistics about a file tree
|
||||
# Usage: file_stats [options] [path]
|
||||
# Options:
|
||||
# -H, --human Human readable sizes\n"
|
||||
# -H, --human Human readable sizes
|
||||
# -d, --details Display details (min/max/average/median)
|
||||
# -m, --average Display only average size
|
||||
# -M, --median Display only median size
|
||||
@@ -394,9 +445,8 @@ file_stats()
|
||||
disp E "Invalid options, use \"file_stats --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
local -a _pargs=()
|
||||
readarray -td '' _pargs < <(printf '%s' "$PARSED" | xargs printf '%s\0')
|
||||
set -- "${_pargs[@]}"
|
||||
# Restore the getopt-normalised (shell-quoted) argument list
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
@@ -476,16 +526,23 @@ file_stats()
|
||||
done
|
||||
|
||||
[[ -n "$1" ]] && path="$1"
|
||||
if [[ ! -e "$path" ]]; then
|
||||
disp E "file_stats: no such file or directory: ${path}"
|
||||
return 1
|
||||
fi
|
||||
# "./" keeps a name starting with "-" from being read as a find option
|
||||
[[ $path == -* ]] && path="./$path"
|
||||
|
||||
# Prepare find filters
|
||||
local find_cmd=(find "$path" -type f)
|
||||
|
||||
# Single extension filter
|
||||
# Single extension filter (case-insensitive). When combined with
|
||||
# --ext-list, a file must satisfy both, as find ANDs the tests.
|
||||
if [[ -n "$ext_filter" ]]; then
|
||||
find_cmd+=(-iname "*.$ext_filter")
|
||||
fi
|
||||
|
||||
# Extension list filter
|
||||
# Extension list filter: ( -iname *.a -o -iname *.b ... )
|
||||
local exts
|
||||
if [[ -n "$ext_list" ]]; then
|
||||
IFS=',' read -ra exts <<< "$ext_list"
|
||||
@@ -507,20 +564,35 @@ file_stats()
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
local bytes
|
||||
if [[ -n "$min_size" ]]; then
|
||||
find_cmd+=(-size +"$(numfmt --from=iec "$min_size")"c)
|
||||
bytes=$(numfmt --from=iec "$min_size" 2>/dev/null) || {
|
||||
disp E "file_stats: invalid --min size: ${min_size}"
|
||||
return 1
|
||||
}
|
||||
# find's "-size +N" means "strictly more than N bytes"; the minimum
|
||||
# is inclusive, hence N-1 (nothing to filter for a minimum of 0).
|
||||
(( bytes > 0 )) && find_cmd+=(-size +"$(( bytes - 1 ))"c)
|
||||
fi
|
||||
if [[ -n "$max_size" ]]; then
|
||||
find_cmd+=(-size -"$(( $(numfmt --from=iec "$max_size") + 1 ))"c)
|
||||
bytes=$(numfmt --from=iec "$max_size" 2>/dev/null) || {
|
||||
disp E "file_stats: invalid --max size: ${max_size}"
|
||||
return 1
|
||||
}
|
||||
# "-size -N" means "less than N bytes": N+1 makes the maximum inclusive.
|
||||
find_cmd+=(-size -"$(( bytes + 1 ))"c)
|
||||
fi
|
||||
|
||||
# Execution
|
||||
# Execution: one size per line, sorted ascending (the median needs it),
|
||||
# then summarised by awk. The path goes through ENVIRON, as awk -v would
|
||||
# interpret backslashes in it.
|
||||
"${find_cmd[@]}" -printf "%s\n" 2>/dev/null | sort -n | \
|
||||
FILE_STATS_PATH="$path" \
|
||||
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) {
|
||||
-v only_total="$only_total" -v show_all="$show_all" '
|
||||
# Convert function (i and units are local: extra parameters)
|
||||
function human_readable(x, i, units) {
|
||||
split("B KiB MiB GiB TiB", units)
|
||||
i = 1
|
||||
while (x >= 1024 && i < 5) {
|
||||
@@ -541,14 +613,17 @@ file_stats()
|
||||
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]++
|
||||
}
|
||||
# Histogram bucket b holds sizes in [1024^b, 1024^(b+1)); bucket 0
|
||||
# also takes empty files. Computed with an integer loop: a
|
||||
# log() ratio can fall just below an exact power of 1024.
|
||||
v = $1; b = 0
|
||||
while (v >= 1024) { v = int(v / 1024); b++ }
|
||||
bucket[b]++
|
||||
if (b > maxb) maxb = b
|
||||
}
|
||||
|
||||
END {
|
||||
path = ENVIRON["FILE_STATS_PATH"]
|
||||
count = NR
|
||||
if (count == 0) {
|
||||
print "No files found."
|
||||
@@ -584,8 +659,10 @@ file_stats()
|
||||
if (details) {
|
||||
print "\nSize histogram:"
|
||||
|
||||
# Use a separate array for the loop to avoid collision
|
||||
for (b in bucket) {
|
||||
# Walk the buckets in ascending order (awk "for (b in array)" gives
|
||||
# no defined order); empty buckets are skipped.
|
||||
for (b = 0; b <= maxb; b++) {
|
||||
if (!(b in bucket)) continue
|
||||
# Pre-calculate label parts
|
||||
# 1024^0 = 1 (B), 1024^1 = 1K, etc.
|
||||
low = (b == 0) ? 0 : (1024^b)
|
||||
@@ -595,7 +672,6 @@ file_stats()
|
||||
(b == 0) ? "0" : human_readable(low),
|
||||
human_readable(high))
|
||||
|
||||
# We store buckets in an array, access them by index b
|
||||
printf "%-25s : %6d files\n", label, bucket[b]
|
||||
}
|
||||
}
|
||||
@@ -624,9 +700,8 @@ findbig()
|
||||
disp E "Invalid options, use \"findbig --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
local -a _pargs=()
|
||||
readarray -td '' _pargs < <(printf '%s' "$PARSED" | xargs printf '%s\0')
|
||||
set -- "${_pargs[@]}"
|
||||
# Restore the getopt-normalised (shell-quoted) argument list
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
@@ -646,10 +721,6 @@ findbig()
|
||||
;;
|
||||
-l|--limit)
|
||||
limit="$2"
|
||||
[[ "$limit" =~ ^[0-9]+$ ]] || {
|
||||
disp E "Invalid limit: must be a positive integer."
|
||||
return 1
|
||||
}
|
||||
shift 2
|
||||
;;
|
||||
-x|--one-fs)
|
||||
@@ -667,7 +738,16 @@ findbig()
|
||||
esac
|
||||
done
|
||||
|
||||
# Checked here so that the configured default (FINDBIG_DEFAULT_LIMIT) is
|
||||
# validated as well as -l.
|
||||
if [[ ! "$limit" =~ ^[1-9][0-9]*$ ]]; then
|
||||
disp E "Invalid limit '${limit}': must be a positive integer."
|
||||
return 1
|
||||
fi
|
||||
|
||||
local dir="${1:-.}"
|
||||
# "./" keeps a name starting with "-" from being read as a find option
|
||||
[[ $dir == -* ]] && dir="./$dir"
|
||||
|
||||
# Prepare find arguments in an array for cleaner handling
|
||||
local find_args=(-L "$dir")
|
||||
@@ -731,9 +811,8 @@ findzero()
|
||||
disp E "Invalid options, use \"findzero --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
local -a _pargs=()
|
||||
readarray -td '' _pargs < <(printf '%s' "$PARSED" | xargs printf '%s\0')
|
||||
set -- "${_pargs[@]}"
|
||||
# Restore the getopt-normalised (shell-quoted) argument list
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
@@ -770,7 +849,18 @@ findzero()
|
||||
done
|
||||
|
||||
local dir="${1:-.}"
|
||||
local find_args=("-L" "$dir" "-type" "f" "-empty")
|
||||
# "./" keeps a name starting with "-" from being read as a find option
|
||||
[[ $dir == -* ]] && dir="./$dir"
|
||||
|
||||
# Symlinks are followed to report/count empty targets, but never when
|
||||
# deleting: with -L, a link to an empty file matches and "delete" would
|
||||
# remove the link itself.
|
||||
local follow=1
|
||||
(( delete )) && follow=0
|
||||
|
||||
local find_args=()
|
||||
(( follow )) && find_args+=("-L")
|
||||
find_args+=("$dir" "-type" "f" "-empty")
|
||||
|
||||
(( one_fs )) && find_args+=("-xdev")
|
||||
|
||||
@@ -779,13 +869,19 @@ findzero()
|
||||
_fd=$(command -v fd 2>/dev/null || command -v fdfind 2>/dev/null)
|
||||
|
||||
if [[ -n "$_fd" ]]; then
|
||||
local _fd_args=(--follow --no-ignore --hidden --absolute-path -t f --size -1b)
|
||||
local _fd_args=(--no-ignore --hidden --absolute-path -t f --size -1b)
|
||||
(( follow )) && _fd_args+=(--follow)
|
||||
(( one_fs )) && _fd_args+=(--one-file-system)
|
||||
_fd_args+=(. "$dir")
|
||||
# fd's "--size -1b" means "at most 1 byte", so it also lists files of
|
||||
# exactly one byte. Every result is therefore re-checked with [[ -s ]]
|
||||
# (true when the size is not zero) and skipped if not empty: deleting a
|
||||
# one-byte file would be data loss.
|
||||
if (( delete )); then
|
||||
disp W "Deleting empty files in $dir..."
|
||||
local f
|
||||
"$_fd" "${_fd_args[@]}" 2>/dev/null | while IFS= read -r f; do
|
||||
[[ -s "$f" ]] && continue
|
||||
printf "%s\n" "$f"
|
||||
rm -f -- "$f"
|
||||
done
|
||||
@@ -793,11 +889,16 @@ findzero()
|
||||
elif (( details )); then
|
||||
local f
|
||||
"$_fd" "${_fd_args[@]}" 2>/dev/null | while IFS= read -r f; do
|
||||
[[ -s "$f" ]] && continue
|
||||
ls -ls -- "$f"
|
||||
done
|
||||
unset f
|
||||
else
|
||||
"$_fd" "${_fd_args[@]}" 2>/dev/null
|
||||
local f
|
||||
"$_fd" "${_fd_args[@]}" 2>/dev/null | while IFS= read -r f; do
|
||||
if [[ ! -s "$f" ]]; then printf "%s\n" "$f"; fi
|
||||
done
|
||||
unset f
|
||||
fi
|
||||
elif (( delete )); then
|
||||
disp W "Deleting empty files in $dir..."
|
||||
@@ -831,9 +932,8 @@ finddead()
|
||||
disp E "Invalid options, use \"finddead --help\" to display usage."
|
||||
return 1
|
||||
fi
|
||||
local -a _pargs=()
|
||||
readarray -td '' _pargs < <(printf '%s' "$PARSED" | xargs printf '%s\0')
|
||||
set -- "${_pargs[@]}"
|
||||
# Restore the getopt-normalised (shell-quoted) argument list
|
||||
eval set -- "$PARSED"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
@@ -870,6 +970,8 @@ finddead()
|
||||
done
|
||||
|
||||
local dir="${1:-.}"
|
||||
# "./" keeps a name starting with "-" from being read as a find option
|
||||
[[ $dir == -* ]] && dir="./$dir"
|
||||
# -xtype l searches for links that do not point to an existing file
|
||||
local find_args=("$dir" "-xtype" "l")
|
||||
(( one_fs )) && find_args+=("-xdev")
|
||||
@@ -887,19 +989,19 @@ finddead()
|
||||
disp W "Deleting dead symlinks in $dir..."
|
||||
local f
|
||||
"$_fd" "${_fd_args[@]}" 2>/dev/null | while IFS= read -r f; do
|
||||
[[ -e "$f" ]] || { printf "%s\n" "$f"; rm -f -- "$f"; }
|
||||
if [[ ! -e "$f" ]]; then printf "%s\n" "$f"; rm -f -- "$f"; fi
|
||||
done
|
||||
unset f
|
||||
elif (( details )); then
|
||||
local f
|
||||
"$_fd" "${_fd_args[@]}" 2>/dev/null | while IFS= read -r f; do
|
||||
[[ -e "$f" ]] || ls -ls -- "$f"
|
||||
if [[ ! -e "$f" ]]; then ls -ls -- "$f"; fi
|
||||
done
|
||||
unset f
|
||||
else
|
||||
local f
|
||||
"$_fd" "${_fd_args[@]}" 2>/dev/null | while IFS= read -r f; do
|
||||
[[ -e "$f" ]] || printf "%s\n" "$f"
|
||||
if [[ ! -e "$f" ]]; then printf "%s\n" "$f"; fi
|
||||
done
|
||||
unset f
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user