Recycle Bin / Trash Can Functionality for the Linux Shell
Posted: Sat Oct 06, 2007 3:15 pm
Since I've discovered that it is possible to have this kind of functionality for Samba I've wanted to create a shell utility for moving files to a trash can rather than deleting them forever. I found a simple implementation but I wanted something a little more complete. So I've taken this as an opportunity to actually write something of generalised use in bash.
So I'm posting this for critique and advise, and possibly to see if anyone wants to help me write this, it's a pretty small project and an opportunity to learn a bit about shell scripting. I've read this article about writing good Linux utilities and this about the GNU/POSIX utility guidelines. So I'm enclosing my design here in the hope that more experienced Linuxers
may be able to offer some conceptual advice.
Note: I haven't written any actual code yet
can
the overall name for the utility is "can" which you can take to loosely mean "put in a trash can". Note 'a' and not 'the'. This is a easy to type, remember and say and is related to what it does. It isn't obvious what it does until you know of it but then not many Unix utilities are. I considered "trsh" but that sounds like a shell. I considered "bin" but that already means binary. "throwout" or "thrwt" or chuck are longer and no more obvious in meaning.
I've tried to generalise my design to be: a way of moving stuff to a place where it can be easily restored from for only a limited time; so I like the way you can think of "can " to mean trash-can or "can" in the more general form as being a container. Of course "can" is a common english word so that's a bit annoying for this post but later on I can't see it as being a problem. The word also functions nicely as a verb: "I don't need that any more; can it"
Summary of Functionality
There are 3 scripts involved in this:
When you can files you may specify a --purge-after (-p) option to determine how long the file should hang around for. If this option is omitted the default value is used. You may specify a --purge-after of 0 or -1 to keep the file indefinitely. A new log file is created for each can operation containing the list of files that were canned, how long they should be kept for and when the can occurred. The log files will have the mode of 0400 and are stored in a dir ".canlogs" . A typical can log might look like this:First is the date those files where deleted, then a colon, then how long they should stay around then on the new lines the deleted file paths.
If this should occur:can will fail saying that foo is already in the trash. You may force it with -f to perform the can overwriting the old version of foo in the process.
Configuration and Hooks
can, ucan and pcan are all configured by a file ".can" in the user's home directory, if this isn't found a system-wide file "/etc/can.conf" is used. The configuration files looks very much like ini files and are sectioned into blocks that may inherit from each other. There are only a handful of directives. A commented example file is shown below:
As you can see in this configuration there are three blocks: default, foo and bar. You may specify which configuration you use in the -c option. Users can use this to direct their files to several trash cans if they wish.
Technical notes:
So I'm posting this for critique and advise, and possibly to see if anyone wants to help me write this, it's a pretty small project and an opportunity to learn a bit about shell scripting. I've read this article about writing good Linux utilities and this about the GNU/POSIX utility guidelines. So I'm enclosing my design here in the hope that more experienced Linuxers
Note: I haven't written any actual code yet
can
the overall name for the utility is "can" which you can take to loosely mean "put in a trash can". Note 'a' and not 'the'. This is a easy to type, remember and say and is related to what it does. It isn't obvious what it does until you know of it but then not many Unix utilities are. I considered "trsh" but that sounds like a shell. I considered "bin" but that already means binary. "throwout" or "thrwt" or chuck are longer and no more obvious in meaning.
I've tried to generalise my design to be: a way of moving stuff to a place where it can be easily restored from for only a limited time; so I like the way you can think of "can " to mean trash-can or "can" in the more general form as being a container. Of course "can" is a common english word so that's a bit annoying for this post but later on I can't see it as being a problem. The word also functions nicely as a verb: "I don't need that any more; can it"
Summary of Functionality
There are 3 scripts involved in this:
- can - moves files to a trash can
- ucan - restores files from a trash can
- pcan - (purge can) this is usually executed daily, using cron, that permanently deletes files in the trash can if they have reached a certain age
When you can files you may specify a --purge-after (-p) option to determine how long the file should hang around for. If this option is omitted the default value is used. You may specify a --purge-after of 0 or -1 to keep the file indefinitely. A new log file is created for each can operation containing the list of files that were canned, how long they should be kept for and when the can occurred. The log files will have the mode of 0400 and are stored in a dir ".canlogs" . A typical can log might look like this:
Code: Select all
2007-10-06 16:46:12,20
/home/zim/foo.txt
/home/zim/bar.txtIf this should occur:
Code: Select all
$ touch foo
$ can foo
$ touch foo
$ can fooConfiguration and Hooks
can, ucan and pcan are all configured by a file ".can" in the user's home directory, if this isn't found a system-wide file "/etc/can.conf" is used. The configuration files looks very much like ini files and are sectioned into blocks that may inherit from each other. There are only a handful of directives. A commented example file is shown below:
Code: Select all
####
# can.conf
#
# the default configuration set
[default]
# where trashed files go
trashcan=~/.trash
# number of days trashed files remain in existance
# set to 0 for no purge, this still permits user to use
# purge in their invocation of can
purge_after=45
# the highest number a user can use when specifying
# their own --purge-after. 0 for no maximum
max_purge_override=0
# the lowest number a user can use when specifying
# their own --purge-after. 0 for no minimum
min_purge_override=0
# Hooks
#
# These are scripts that we executed either before (pre)
# or after (post) can or ucan. These will be invoked once
# for each file being moved by can or ucan unless otherwise stated
# before can
# $1 will be full filepath
# $2 onwards are any --pre-args specified by the can invocation
#
# You may exit with a status number to communicate with can:
# 0: continue with can - assumed
# 1: abort the can and suppress execution of post_can_hook for this file
# 2: abort the can and suppress execution of post_can_hook for this file
# and all others in this invocation of can
# 3: do not can, purge right away
pre_can_hook=''
# after can
# $1 will be the full file path
# $2 onwards are any --post-args specified by the can invocation
post_can_hook=''
# before ucan
# $1 is the full file path where it was deleted from
# $2 is the full destination file path (not necessarily the same as $1)
# $3 onwards are any --pre-args specified
#
# You may exit with a status number to communicate with ucan:
# 0: continue with ucan - assumed
# 1: abort the ucan and suppress execution of post_ucan_hook for this file
# 2: abort the ucan and suppress execution of post_ucan_hook
# for this file and all others in this invocation of ucan
pre_ucan_hook=''
# after ucan
# $1 is the full file path where it was deleted from
# $2 is the full destination file path (not necessarily the same as $1)
# $3 onwards are any --post-args specified
post_ucan_hook=''
# implements an alternate configuration set called 'foo' that
# inherits the options from upon default
[foo : default]
# deviation from default
trashcan=/tmp/trash
# another configuration not inheriting from anything
[bar]
# this will prevent this configuration set from being executed. You may wish
# to use this on default if you want to force your users to specify wish
# configuration to use
disabled=1
Technical notes:
- Because can create logs in ".canlogs" under the trash can dir you will be denied the ability to can anything called "/.canlogs"
- If pcan encounters a file in a log that is not present in the trash can it will ignore it and carry on, assuming it has probably been restored
Code: Select all
Usage: can [OPTION]... FILE...
Recursively moves files or directories to a trash can
-c --config=CONFIG specifies which set of configuration directive should apply
-f --force cans even if something with same name and path already exists in trash can
-v --verbose show the files being canned
-p --purge-after=DAYS set the number of day the files will remain
in the trash before being purged (rm'd)
-r --pre-args=ARGS args to send to the pre_hock_script
-o --post-args=ARGS args to send to the post_hock_script
-h --help display this help textCode: Select all
Usage: ucan [OPTION]... FILE... [DEST]
Restore files or directories from the trash can
FILEs and DEST are relative to . unless absolute
-c --config=CONFIG specifies which set of configuration directive should apply
-r --pre-args=ARGS args to send to the pre_hock_script
-o --post-args=ARGS args to send to the post_hock_scriptCode: Select all
Usage: pcan [-c config|-a] [-e]
Deletes the current user's canned files that are due to be purged.
-c --config=CONFIG specifies which set of configuration directive should apply
-a --all purges all users canned files
-e --empty completely empties the trash of everything even regardless