dotfiles/.config/shell/bin/rm-prefer-trash

170 lines
3.9 KiB
Bash
Executable file

#!/bin/sh
# cause plain rm wasn't good enough
# auto selects what trash directory to put files in if rmtrash is available
# otherwise, uses rm
set -eu
rm='rm'
err_differing_filesystems() {
echo 'Error: some files are apart of different filesystems.' >&2
# shellcheck disable=SC2016
echo 'Either set RM=rm to force not using `trash`, or remove the files individually' >&2
}
fs(){
df "$1" | sed '1d' | cut -d ' ' -f 1
}
dbg() {
echo "$@" >&2
}
rm_warning() {
echo 'WARNING: using rm - NOT trash. Files will be PERMINANTLY DELETED!' >&2
printf '%s' "Type Y to continue: " >&2
read -r confirm
if [ "$confirm" != 'Y' ]; then
printf '\n'
exit 1
fi
echo 'Waiting 3 seconds before continuing.' >&2
sleep 3
}
rm_custom_warning() {
echo 'WARNING: using custom rm command: '"$rm" >&2
echo 'This might NOT use the trash'
echo ''
echo 'Waiting 5 seconds before continuing.' >&2
sleep 5
}
err_no_trashdirs() {
echo 'Error: No trash directorys with matching filesystems are available.' >&2
echo 'Please set TRASH_DIRS to a colon-separated list of your preferred trash directories.' >&2
}
usage() {
echo "Wrapper for rm and rm-trash commands"
echo ""
echo "Environment:"
echo " RM Force using a particular rm command."
# shellcheck disable=SC2016
echo ' TRASH_DIRS What directories to use as trash locations for `trash`.'
echo ' DRY Dry run: print the rm command instead of executing it.'
echo ""
echo "Usage:"
echo " ${0##*/} [ARGS]"
echo ""
echo "Where ARGS is the argument list corresponding to the rm command to be used."
echo ""
echo "Current selection for rm command: $which_rm"
}
do_rm() {
if [ "${DRY:-false}" = true ]; then
echo "$rm" "$@"
else
"$rm" "$@"
fi
}
do_rmnormal() {
# shellcheck disable=SC2209
rm=rm
rm_warning
do_rm "$@"
}
do_rmcustom() {
# check if we have been given an rm command
rm="$RM"
rm_custom_warning
do_rm "$@"
}
do_rmtrash() {
# get trash directories
trash_default_fallback="$HOME"/.local/share
trash_default="${XDG_DATA_HOME:-"$trash_default_fallback"}/Trash"
trashdirs="${TRASH_DIRS:-"$trash_default"}"
# if trash is available, use it
rm='trash'
fs1=''
# validate that all files are on the same filesystem
for a; do
if [ -e "$a" ]; then
fs="$(fs "$a")"
if [ -z "$fs1" ]; then
fs1="$fs"
# this will only run the first time through the loop
continue
fi
# ensure all files are on the same filesystem
if [ "$fs1" != "$fs" ]; then
err_differing_filesystems
exit 1
fi
fi
done
if [ "$fs1" != '' ]; then
# if we get here, we have validated that all the files are on the same filesystem
trashdir=''
found_trash=false
while [ "$trashdirs" != "$trashdir" ]; do
trashdir="${trashdirs%%:*}"
trashdirs="${trashdirs#"$trashdir":}"
fs="$(fs "$trashdir")"
if [ "$fs" = "$fs1" ]; then
found_trash=true
break
fi
done
if [ "$found_trash" = true ]; then
set -- --trash-dir "$trashdir" "$@"
else
err_no_trashdirs
exit 1
fi
fi
echo "trash dir:" "$trashdir"
do_rm "$@"
}
main() {
# which rm command to use
rm=''
# calculate which rm command to use
which_rm=''
if [ -n "${RM:-}" ]; then
which_rm='custom: '"$RM"
elif command -v trash > /dev/null; then
which_rm='trash'
else
which_rm='rm'
fi
# print usage information (including which rm command we'll use)
if [ $# = 0 ]; then
usage
exit
fi
# execute rm
case "$which_rm" in
rm)
do_rmnormal "$@";;
trash)
do_rmtrash "$@";;
custom*)
do_rmcustom "$@";;
*)
usage; exit;;
esac
}
main "$@"