Standardized indentation and moved url encoding/decoding to a more
standardized location.
This commit is contained in:
parent
f154424db2
commit
9d18bcc775
419
bin
419
bin
@ -26,243 +26,269 @@ force_flag=
|
||||
[ -z "$RS" ] && RS='\n'
|
||||
|
||||
fail() {
|
||||
echo "$@" 1>&2
|
||||
exit 1
|
||||
echo "$@" 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
show_usage() {
|
||||
cat << EOU
|
||||
Usage: $progname [OPTION]... FILE...
|
||||
cat <<-EOU
|
||||
Usage: $progname [OPTION]... FILE...
|
||||
|
||||
Move files into the trash bin.
|
||||
Move files into the trash bin.
|
||||
|
||||
Options:
|
||||
-h, --help show this help message and exit
|
||||
-V, --version show program's version number and exit
|
||||
-v, --verbose explain what is being done
|
||||
-i, --interactive prompt before moving every file
|
||||
-f, --force ignore non-existent files, never prompt
|
||||
-r, -R, --recursive ignored (for compatability with rm)
|
||||
-u, --untrash restore file(s) from the trash
|
||||
-e, --empty choose files to empty from the trash
|
||||
-E, --empty-all empty all the files in the trash folder(s) (default: ~)
|
||||
-l, --list list files in trash folder(s) (default: ~)
|
||||
-- Any arguments after '--' will be treated as filenames
|
||||
EOU
|
||||
Options:
|
||||
-h, --help show this help message and exit
|
||||
-V, --version show program's version number and exit
|
||||
-v, --verbose explain what is being done
|
||||
-i, --interactive prompt before moving every file
|
||||
-f, --force ignore non-existent files, never prompt
|
||||
-r, -R, --recursive ignored (for compatability with rm)
|
||||
-u, --untrash restore file(s) from the trash
|
||||
-e, --empty choose files to empty from the trash
|
||||
-E, --empty-all empty all the files in the trash folder(s) (default: ~)
|
||||
-l, --list list files in trash folder(s) (default: ~)
|
||||
-- Any arguments after '--' will be treated as filenames
|
||||
EOU
|
||||
}
|
||||
|
||||
find_trashfile() {
|
||||
target0="$1"
|
||||
target="$(readlink -f -- "$target0")"
|
||||
td="$(get_trashdir "$target")"
|
||||
if [ "$(dirname "$target")" = "$td/files" ] && [ -e "$target" ]; then
|
||||
echo "$target"
|
||||
else
|
||||
best_file=
|
||||
best_date=0
|
||||
for f in "$td/files"/*; do
|
||||
[ -e "$f" ] || continue
|
||||
info="$td/info/$(basename "$f").trashinfo"
|
||||
path="$(path_from_trashinfo "$info")"
|
||||
date="$(date +"%s" -d "$(date_from_trashinfo "$info")")"
|
||||
if [ "$path" = "$target" -a \( -z "$best_file" -o "$date" -gt "$best_date" \) ]; then
|
||||
best_file="$f"
|
||||
best_date="$date"
|
||||
fi
|
||||
done
|
||||
[ -z "$best_file" ] && return 1
|
||||
echo "$best_file"
|
||||
fi
|
||||
target0="$1"
|
||||
target="$(readlink -f -- "$target0")"
|
||||
td="$(get_trashdir "$target")"
|
||||
if [ "$(dirname "$target")" = "$td/files" ] && [ -e "$target" ]; then
|
||||
echo "$target"
|
||||
else
|
||||
best_file=
|
||||
best_date=0
|
||||
for f in "$td/files"/*; do
|
||||
[ -e "$f" ] || continue
|
||||
info="$td/info/$(basename "$f").trashinfo"
|
||||
path="$(path_from_trashinfo "$info")"
|
||||
date="$(date +"%s" -d "$(date_from_trashinfo "$info")")"
|
||||
if [ "$path" = "$target" -a \( -z "$best_file" -o "$date" -gt "$best_date" \) ]; then
|
||||
best_file="$f"
|
||||
best_date="$date"
|
||||
fi
|
||||
done
|
||||
[ -z "$best_file" ] && return 1
|
||||
echo "$best_file"
|
||||
fi
|
||||
}
|
||||
|
||||
confirm() {
|
||||
[ "$force_flag" = "-f" ] && return 0
|
||||
if type ask >/dev/null; then
|
||||
ask -n "$@"
|
||||
else
|
||||
# Get one character of input
|
||||
tput civis >/dev/tty;
|
||||
printf '\033[1m%s\033[0m' "$2" >/dev/tty;
|
||||
stty -icanon -echo >/dev/tty 2>/dev/tty;
|
||||
REPLY="$(dd bs=1 count=1 2>/dev/null </dev/tty)"
|
||||
stty icanon echo >/dev/tty 2>/dev/tty
|
||||
tput cvvis >/dev/tty
|
||||
[ "$REPLY" = "y" ]
|
||||
fi
|
||||
[ "$force_flag" = "-f" ] && return 0
|
||||
if type ask >/dev/null; then
|
||||
ask -n "$@"
|
||||
else
|
||||
# Get one character of input
|
||||
tput civis >/dev/tty;
|
||||
printf '\033[1m%s\033[0m' "$2" >/dev/tty;
|
||||
stty -icanon -echo >/dev/tty 2>/dev/tty;
|
||||
REPLY="$(dd bs=1 count=1 2>/dev/null </dev/tty)"
|
||||
stty icanon echo >/dev/tty 2>/dev/tty
|
||||
tput cvvis >/dev/tty
|
||||
[ "$REPLY" = "y" ]
|
||||
fi
|
||||
}
|
||||
|
||||
has_arg() {
|
||||
if type arg >/dev/null; then
|
||||
arg "$@" >/dev/null
|
||||
else
|
||||
target="$1"
|
||||
while [ $# -gt 0 ]; do
|
||||
[ "$1" = "$target" ] && return 0
|
||||
[ "$1" = "--" ] && break
|
||||
done
|
||||
false
|
||||
fi
|
||||
if type arg >/dev/null; then
|
||||
arg "$@" >/dev/null
|
||||
else
|
||||
target="$1"
|
||||
while [ $# -gt 0 ]; do
|
||||
[ "$1" = "$target" ] && return 0
|
||||
[ "$1" = "--" ] && break
|
||||
done
|
||||
false
|
||||
fi
|
||||
}
|
||||
|
||||
encoder=
|
||||
if command -v php &> /dev/null; then
|
||||
encoder=php
|
||||
elif command -v python3 &> /dev/null; then
|
||||
encoder=python
|
||||
elif command -v perl &> /dev/null; then
|
||||
encoder=perl
|
||||
else
|
||||
echo "No URL encoder found! Please install php, python3, or perl!" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
urlencode() {
|
||||
case "$encoder" in
|
||||
php) php -r 'echo urlencode($argv[1]);' -- "$1" ;;
|
||||
perl) perl -MURI::Escape -e 'print uri_escape $ARGV[0]' -- "$1" ;;
|
||||
python) python3 -c 'import urllib.parse, sys; print(urllib.parse.quote(sys.argv[1]))' "$1";;
|
||||
esac
|
||||
}
|
||||
|
||||
urldecode() {
|
||||
case "$encoder" in
|
||||
php) php -r 'echo urldecode($argv[1]);' -- "$1" ;;
|
||||
perl) perl -MURI::Escape -e 'print uri_unescape $ARGV[0]' -- "$1" ;;
|
||||
python) python3 -c 'import urllib.parse, sys; print(urllib.parse.unquote(sys.argv[1]))' "$1";;
|
||||
esac
|
||||
}
|
||||
|
||||
is_valid_trashdir() {
|
||||
[ -d "$1" ] && expr "$(stat -c '%a' "$1")" : '^1[0-7]\{3\}' >/dev/null && ! [ -L "$1" ]
|
||||
[ -d "$1" ] && expr "$(stat -c '%a' "$1")" : '^1[0-7]\{3\}' >/dev/null && ! [ -L "$1" ]
|
||||
}
|
||||
|
||||
get_trashdir() {
|
||||
file="$(readlink -f -- "$1")"
|
||||
if [ -e "$file" ]; then
|
||||
file_base="$(df -h "$file" | awk 'NR==2 {print $NF}')"
|
||||
else
|
||||
file_base="$(awk -v f="$file" 'substr(f,1,length($2)+1)==($2 "/") && $2>best {best=$2} END {print best}' /proc/mounts)"
|
||||
fi
|
||||
home_base="$(df -h "$HOME" | awk 'NR==2 {print $NF}')"
|
||||
if [ "$file_base" = "$home_base" ]; then
|
||||
echo "$HOME/.Trash"
|
||||
elif is_valid_trashdir "$file_base/.Trash"; then
|
||||
echo "$file_base/.Trash"
|
||||
else
|
||||
echo "$file_base/.Trash-$(id -u)"
|
||||
fi
|
||||
file="$(readlink -f -- "$1")"
|
||||
if [ -e "$file" ]; then
|
||||
file_base="$(df -h "$file" | awk 'NR==2 {print $NF}')"
|
||||
else
|
||||
file_base="$(awk -v f="$file" 'substr(f,1,length($2)+1)==($2 "/") && $2>best {best=$2} END {print best}' /proc/mounts)"
|
||||
fi
|
||||
home_base="$(df -h "$HOME" | awk 'NR==2 {print $NF}')"
|
||||
if [ "$file_base" = "$home_base" ]; then
|
||||
echo "$HOME/.Trash"
|
||||
elif is_valid_trashdir "$file_base/.Trash"; then
|
||||
echo "$file_base/.Trash"
|
||||
else
|
||||
echo "$file_base/.Trash-$(id -u)"
|
||||
fi
|
||||
}
|
||||
|
||||
can_trash() {
|
||||
filename="$1"
|
||||
if [ ! -e "$filename" ]; then
|
||||
if [ "$force_flag" != "-f" ]; then
|
||||
fail "$progname: cannot move '$filename' to trash: No such file or directory"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
filename="$1"
|
||||
if [ ! -e "$filename" ]; then
|
||||
if [ "$force_flag" != "-f" ]; then
|
||||
fail "$progname: cannot move '$filename' to trash: No such file or directory"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "$interactive_flag" = "-i" ]; then
|
||||
[ -d "$filename" ] && type=directory || type="file"
|
||||
confirm "$progname: move $type '$filename' to trash?"
|
||||
fi
|
||||
if [ "$interactive_flag" = "-i" ]; then
|
||||
[ -d "$filename" ] && type=directory || type="file"
|
||||
confirm "$progname: move $type '$filename' to trash?"
|
||||
fi
|
||||
}
|
||||
|
||||
init_trashdir() {
|
||||
trashdir=$1
|
||||
if ! [ -d "$trashdir" ]; then
|
||||
mkdir -m 1755 "$trashdir" || fail "Could not create trash directory"
|
||||
fi
|
||||
mkdir -p "$trashdir/files" || fail "$progname: unable to write to $trashdir"
|
||||
mkdir -p "$trashdir/info" || fail "$progname: unable to write to $trashdir"
|
||||
trashdir=$1
|
||||
if ! [ -d "$trashdir" ]; then
|
||||
mkdir -m 1755 "$trashdir" || fail "Could not create trash directory"
|
||||
fi
|
||||
mkdir -p "$trashdir/files" || fail "$progname: unable to write to $trashdir"
|
||||
mkdir -p "$trashdir/info" || fail "$progname: unable to write to $trashdir"
|
||||
}
|
||||
|
||||
path_from_trashinfo() {
|
||||
#sed -n 's/^Path=//p' "$1" | php -r 'echo urldecode(fgets(STDIN));'
|
||||
sed -n 's/^Path=//p' "$1" | perl -MURI::Escape -ne 'print uri_unescape $_'
|
||||
urldecode "$(sed -n 's/^Path=//p' "$1")"
|
||||
}
|
||||
|
||||
date_from_trashinfo() {
|
||||
sed -n 's/^DeletionDate=//p' "$1"
|
||||
sed -n 's/^DeletionDate=//p' "$1"
|
||||
}
|
||||
|
||||
trashinfo_for_file() {
|
||||
#php -r 'echo urlencode($argv[1]);' -- "$1"
|
||||
cat <<END
|
||||
[Trash Info]
|
||||
Path=$(perl -MURI::Escape -e 'print uri_escape $ARGV[0]' -- "$1")
|
||||
DeletionDate=$(date +"%FT%H:%M:%S")
|
||||
END
|
||||
cat <<-END
|
||||
[Trash Info]
|
||||
Path=$(urlencode "$1")
|
||||
DeletionDate=$(date +"%FT%H:%M:%S")
|
||||
END
|
||||
}
|
||||
|
||||
trash_file() {
|
||||
filename=$1
|
||||
dir=${filename%/*}
|
||||
trashdir="$(get_trashdir "$dir")"
|
||||
init_trashdir "$trashdir"
|
||||
filename=$1
|
||||
dir=${filename%/*}
|
||||
trashdir="$(get_trashdir "$dir")"
|
||||
init_trashdir "$trashdir"
|
||||
|
||||
trashname="${filename##*/}"
|
||||
origname="${trashname%%.*}"
|
||||
if [ -z "$origname" ]; then
|
||||
origname="dotfile"
|
||||
fi
|
||||
ext=".${trashname##*.}"
|
||||
if [ "$ext" = ".$trashname" ]; then
|
||||
ext=""
|
||||
fi
|
||||
trashname="${filename##*/}"
|
||||
origname="${trashname%%.*}"
|
||||
if [ -z "$origname" ]; then
|
||||
origname="dotfile"
|
||||
fi
|
||||
ext=".${trashname##*.}"
|
||||
if [ "$ext" = ".$trashname" ]; then
|
||||
ext=""
|
||||
fi
|
||||
|
||||
# Use -u (unsafe) option because we cannot mv a directory into a
|
||||
# file. This is technically "unsafe" but mv will ask for
|
||||
# confirmation when overwriting.
|
||||
deletedfile=$(mktemp -u "$trashdir/files/${origname}_XXXXXXXX")$ext
|
||||
deletedbase=$(basename "$deletedfile")
|
||||
deletedinfo="$trashdir/info/$deletedbase.trashinfo"
|
||||
# Use -u (unsafe) option because we cannot mv a directory into a
|
||||
# file. This is technically "unsafe" but mv will ask for
|
||||
# confirmation when overwriting.
|
||||
deletedfile=$(mktemp -u "$trashdir/files/${origname}_XXXXXXXX")$ext
|
||||
deletedbase=$(basename "$deletedfile")
|
||||
deletedinfo="$trashdir/info/$deletedbase.trashinfo"
|
||||
|
||||
trashinfo_for_file "$filename" > "$deletedinfo" || \
|
||||
fail "$progname: unable to create trash info for $filename at $deletedinfo"
|
||||
trashinfo_for_file "$filename" > "$deletedinfo" || \
|
||||
fail "$progname: unable to create trash info for $filename at $deletedinfo"
|
||||
|
||||
# Note that the trashinfo file will have the ownership and
|
||||
# permissions of the person who deleted the file, and not
|
||||
# necessarily of the original file.
|
||||
# Note that the trashinfo file will have the ownership and
|
||||
# permissions of the person who deleted the file, and not
|
||||
# necessarily of the original file.
|
||||
|
||||
if ! mv $verbose_flag -- "$filename" "$deletedfile"; then
|
||||
rm "$deletedinfo"
|
||||
fail "$progname: unable to move $filename to $deletedfile"
|
||||
fi
|
||||
if ! mv $verbose_flag -- "$filename" "$deletedfile"; then
|
||||
rm "$deletedinfo"
|
||||
fail "$progname: unable to move $filename to $deletedfile"
|
||||
fi
|
||||
}
|
||||
|
||||
untrash_files() {
|
||||
[ $# -eq 0 ] && fail "No files provided to untrash"
|
||||
for target; do
|
||||
if ! file="$(find_trashfile "$target")"; then
|
||||
[ "$force_flag" = "-f" ] || fail "No such file: $target"
|
||||
fi
|
||||
info="$(dirname "$file")/../info/$(basename "$file").trashinfo"
|
||||
orig="$(path_from_trashinfo "$info")"
|
||||
mv ${force_flag:--i} $verbose_flag "$file" "$orig" || fail "Could not restore file: $file"
|
||||
rm -rf $verbose_flag "$info" || fail "Could not clean up trash info file: $info"
|
||||
done
|
||||
[ $# -eq 0 ] && fail "No files provided to untrash"
|
||||
for target; do
|
||||
if ! file="$(find_trashfile "$target")"; then
|
||||
[ "$force_flag" = "-f" ] || fail "No such file: $target"
|
||||
fi
|
||||
info="$(dirname "$file")/../info/$(basename "$file").trashinfo"
|
||||
orig="$(path_from_trashinfo "$info")"
|
||||
mv ${force_flag:--i} $verbose_flag "$file" "$orig" || fail "Could not restore file: $file"
|
||||
rm -rf $verbose_flag "$info" || fail "Could not clean up trash info file: $info"
|
||||
done
|
||||
}
|
||||
|
||||
empty_files() {
|
||||
[ $# -eq 0 ] && fail "No files provided to empty"
|
||||
for target; do
|
||||
if ! file="$(find_trashfile "$target")"; then
|
||||
[ "$force_flag" = "-f" ] || fail "No such file: $target"
|
||||
fi
|
||||
info="$(dirname "$file")/../info/$(basename "$file").trashinfo"
|
||||
orig="$(path_from_trashinfo "$info")"
|
||||
confirm "Delete file $file?" || exit 1
|
||||
rm -r $force_flag $verbose_flag -- "$file" "$info" || fail "Could not empty file: $file"
|
||||
done
|
||||
[ $# -eq 0 ] && fail "No files provided to empty"
|
||||
for target; do
|
||||
if ! file="$(find_trashfile "$target")"; then
|
||||
[ "$force_flag" = "-f" ] || fail "No such file: $target"
|
||||
fi
|
||||
info="$(dirname "$file")/../info/$(basename "$file").trashinfo"
|
||||
orig="$(path_from_trashinfo "$info")"
|
||||
confirm "Delete file $file?" || exit 1
|
||||
rm -r $force_flag $verbose_flag -- "$file" "$info" || fail "Could not empty file: $file"
|
||||
done
|
||||
}
|
||||
|
||||
empty_trash() {
|
||||
[ $# -eq 0 ] && set "$PWD"
|
||||
for target; do
|
||||
td="$(get_trashdir "$(readlink -f -- "$target")")"
|
||||
[ -d "$td/files" ] && [ -n "$(ls -A "$td/files")" ] || continue
|
||||
[ "$force_flag" != "-f" ] &&
|
||||
( printf '\033[1mThe following %s of files will be deleted:\033[0m\n' \
|
||||
"$(du -h --summarize "$td/files" | cut -f1)B" &&
|
||||
printf ' \033[33m%s\033[0m\n' "$td"/files/*) | more
|
||||
if ! confirm "Do you want to proceed?"; then
|
||||
echo "Aborted."
|
||||
exit 1
|
||||
fi
|
||||
rm -r $verbose_flag "$td"/files/* "$td"/info/* || exit 1
|
||||
printf '\033[1mDeleted!\033[0m\n'
|
||||
done
|
||||
[ $# -eq 0 ] && set "$PWD"
|
||||
for target; do
|
||||
td="$(get_trashdir "$(readlink -f -- "$target")")"
|
||||
[ -d "$td/files" ] && [ -n "$(ls -A "$td/files")" ] || continue
|
||||
[ "$force_flag" != "-f" ] &&
|
||||
( printf '\033[1mThe following %s of files will be deleted:\033[0m\n' \
|
||||
"$(du -h --summarize "$td/files" | cut -f1)B" &&
|
||||
printf ' \033[33m%s\033[0m\n' "$td"/files/*) | more
|
||||
if ! confirm "Do you want to proceed?"; then
|
||||
echo "Aborted."
|
||||
exit 1
|
||||
fi
|
||||
rm -r $verbose_flag "$td"/files/* "$td"/info/* || exit 1
|
||||
printf '\033[1mDeleted!\033[0m\n'
|
||||
done
|
||||
}
|
||||
|
||||
list_trash() {
|
||||
[ $# -eq 0 ] && set "$PWD"
|
||||
for target; do
|
||||
td="$(get_trashdir "$(readlink -f -- "$target")")"
|
||||
for f in "$td/files"/*; do
|
||||
[ -e "$f" ] || continue
|
||||
printf '%s'"$FS"'%s'"$FS"'%s'"$RS" \
|
||||
"$f" "$(date_from_trashinfo "$td/info/$(basename "$f").trashinfo")" \
|
||||
"$(path_from_trashinfo "$td/info/$(basename "$f").trashinfo")"
|
||||
done
|
||||
done
|
||||
[ $# -eq 0 ] && set "$PWD"
|
||||
for target; do
|
||||
td="$(get_trashdir "$(readlink -f -- "$target")")"
|
||||
for f in "$td/files"/*; do
|
||||
[ -e "$f" ] || continue
|
||||
printf '%s'"$FS"'%s'"$FS"'%s'"$RS" \
|
||||
"$f" "$(date_from_trashinfo "$td/info/$(basename "$f").trashinfo")" \
|
||||
"$(path_from_trashinfo "$td/info/$(basename "$f").trashinfo")"
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
show_usage
|
||||
fail "Run 'man $progname' for more information."
|
||||
show_usage
|
||||
fail "Run 'man $progname' for more information."
|
||||
fi
|
||||
|
||||
(has_arg -v "$@" || has_arg --verbose "$@") && verbose_flag=-v
|
||||
@ -277,25 +303,26 @@ action=trash
|
||||
(has_arg -E "$@" || has_arg --empty-all "$@") && action=emptyall
|
||||
|
||||
while a="$(expr ";$1" : "^;\(--\|-[VhvirRfueEl]\+\|--version\|--help\|--verbose\|--interactive\|--recursive\|--force\|--untrash\|--empty\|--empty-all\|--list\)$")"; do
|
||||
shift
|
||||
[ "$a" = "--" ] && break
|
||||
shift
|
||||
[ "$a" = "--" ] && break
|
||||
done
|
||||
|
||||
case "$action" in
|
||||
help) show_usage ;;
|
||||
version) echo "$version" ;;
|
||||
list) list_trash "$@" ;;
|
||||
untrash) untrash_files "$@" ;;
|
||||
emptyfiles) empty_files "$@" ;;
|
||||
emptyall) empty_trash "$@" ;;
|
||||
trash)
|
||||
for f; do
|
||||
filename="$(readlink -f -- "$f")"
|
||||
if ! [ -e "$filename" ]; then
|
||||
[ "$force_flag" = "-f" ] || fail "File does not exist: $filename"
|
||||
else
|
||||
can_trash "$filename" && trash_file "$filename" || exit 1
|
||||
fi
|
||||
done
|
||||
;;
|
||||
help) show_usage ;;
|
||||
version) echo "$version" ;;
|
||||
list) list_trash "$@" ;;
|
||||
untrash) untrash_files "$@" ;;
|
||||
emptyfiles) empty_files "$@" ;;
|
||||
emptyall) empty_trash "$@" ;;
|
||||
trash)
|
||||
for f; do
|
||||
filename="$(readlink -f -- "$f")"
|
||||
if ! [ -e "$filename" ]; then
|
||||
[ "$force_flag" = "-f" ] || fail "File does not exist: $filename"
|
||||
else
|
||||
can_trash "$filename" && trash_file "$filename" || exit 1
|
||||
fi
|
||||
done
|
||||
;;
|
||||
esac
|
||||
# vim: ts=2:noexpandtab:ft=sh
|
||||
|
Loading…
Reference in New Issue
Block a user