I want to replace rm
by a more informative variant: I would like to see which files will be deleted, along with their size, and I would like this information to use the same coloring as ls. As an example (please imagine the coloring):
# remove -r foo/ bar/*
4K bar/file1
1.2M foo/
6.1M bar/file2
remove -r 3 files, 7.3M [yn]? _
I built on suggestions found in another question, and now have a bash script that I begin to like. I have been using it for a few days without noticing any obvious errors. However, I would appreciate any help with making sure that the script will not misbehave in cases I did not foresee.
Here is my code for the coloring:
du_colored (){
# read ls --color output into ls_colored_array
# use \13 as a trick to handle names with spaces
read -d '\n' -r -a ls_colored_array <<< $(ls -Ad --color "$@" | tr " " "\13")
if [[ ${#ls_colored_array[@]} = 0 ]]; then return 1; fi
# - loop over the array and issue du -sh for every element (without coloring)
# - exchange du's ouput with ls's
# - finally sort the output
for i in "${ls_colored_array[@]}"; do
i=`echo $i | tr "\13" " "`
printf '%s' "${i}" | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" | \
xargs -n1 -0 du -sh | awk -v i="$i" '{ printf "%-4s ", $1; print i }'
done | sort -h
}
and the removal script:
# Separate options to rm from 'real' arguments
for i in "$@"; do
case $i in
-*) options+=( "$i" ) ;;
*) toRemove+=( "$i" ) ;;
esac
done
# Print file list
# Abort if no files match
du_colored "${toRemove[@]}"
if [ "_$?" != "_0" ]; then exit 1; fi
# Print summary
count=$(find "${toRemove[@]}" 2>/dev/null | wc -l 2>/dev/null)
size=$(du -sch "${toRemove[@]}" 2>/dev/null | tail -1 | tr '\t' ' ')
plural="s"
if [ $count -eq 1 ]; then plural=""; fi
printf "remove ${options[@]} ($count file$plural, $size) [ny]? " ; read
if [ "_$REPLY" = "_y" ]; then
/bin/rm ${options[@]} ${toRemove[@]}
else
echo '(cancelled)'
fi
- Does this look safe in the sense that what
du_colored
presents is exactly what will be deleted? Both files and directories seem to be treated correctly, even if they include spaces or wildcards. Are there scenarios that I missed? An obvious one are file names that contain a\13
character. - The initial
ls
indu_colored
throws errors for non-existing files, which I like because it mimicks the behavior of regularrm
. However, I currently discard all error messages of the finalfind
andgrep
commands, such that non-existing files do not produce multiple errors. This seems like a dirty trick. Is there a cleaner way? - Bonus question: Is there an easy way to make the output use multiple columns, just as a regular
ls
would? I tried several ways to pipe the output ofdu_colored
to other tools, but either the colors were lost completely or the control characters for the coloring broke the alignment, as they do inls --color | pr -2 -t
.