Skip to content

Instantly share code, notes, and snippets.

@zach-klippenstein
Created May 11, 2010 16:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zach-klippenstein/397489 to your computer and use it in GitHub Desktop.
Save zach-klippenstein/397489 to your computer and use it in GitHub Desktop.
#!/bin/bash
#
# Run periodically by cron, and will unarchive data in the
# ~/auto_unarchive/drop_target directory.
# Where the action happens
unarchiveDir="~/auto_unarchive/drop_target"
# Time in seconds between checking for new archives
checkInterval=1.5
# Total number of seconds the script should run for before
# exiting.
runTime=59
# If non-empty, some extra messages will be logged.
# This should be off for long-term cron use, as it will bloat
# the logs.
verbose=""
# Flag used to log when killed.
cleanExit=""
# Will only run if this file doesn't exist
lockFile="$unarchiveDir/.unarchive.lock"
# Hash table of archive types to their extraction commands.
# The keys are used to grep the output of the file command.
# Used by: getNextArchive,
extractKeys[0]=Zip; extractCmds[0]="unzip"
extractKeys[1]=gzip; extractCmds[1]="gunzip"
function printUsage()
{
local scr="`basename $0`"
echo "usage: $scr [--help | -h]"
}
# Create the unarchive dir if necessary, and return true iff it
# exists.
function setupDir()
{
local targetDir="$1"
if [ ! -d "$targetDir" ]; then
log "Creating auto unarchive directory: $targetDir" <(mkdir "$targetDir")
fi
if [ -d "$targetDir" ]; then
return 0
else
return 1
fi
}
# Returns true only if this instance of the script currently
# owns the lock on the unarchiving directory
function tryLock()
{
if [ ! -f "$lockFile" ]; then
echo "$$" >"$lockFile"
return 0
else
return 1
fi
}
# Releases the lock on the unarchiving directory if this script
# currently holds it
function unlock()
{
# If this instance of the script currently owns the lock
if [ $$ = "$(cat "$lockFile" 2>/dev/null)" ]; then
rm -f "$lockFile"
return 0
fi
return 1
}
# Prints the index of the extract key/command for a file.
# $1 - the filename whose type to search for
function findExtractIndex()
{
fileName="$1"
i=${#extractKeys[*]}
i=$(($i - 1))
if [ "$fileName" ]; then
while [ $i -ge 0 ]; do
key="${extractKeys[$i]}"
if [ "$(file "$line" | grep "$key")" ]; then
echo $i
return 0
fi
i=$(($i - 1))
done
fi
return 1
}
# Prints the absolute path of a relative path, relative to the
# current directory.
# $1 - the path to make absolute
function absolutePath()
{
path="$1"
if [ "$1" ]; then
# Clean leading ./ (e.g. from find command output)
if [ './' = "${path:0:2}" ]; then
path="${path:2}"
fi
# Prepend working dir onto non-absolute paths
if [ '/' != "${path:0:1}" ]; then
echo "$(pwd)/$path"
else
echo "$path"
fi
fi
}
# Prints the extract command for a file, ready-to-run.
# $1 - the file to get the extract command for
# $2 - (optional) the index in the extract table. If not
# specified, will search the table.
function getExtractCmd()
{
fileName="$(absolutePath "$1")"
index="$2"
[ -z "$index" ] && index="$(findExtractIndex "$fileName")"
if [ "$index" ]; then
# Construct the runnable command and return true
echo "${extractCmds[$index]} '$fileName'"
return 0
fi
return 1
}
# Prints the name of an archive in the current directory,
# or nothing if there are no archives.
# If there is an archive, prints the index in the extract
# table on the second line.
function getNextArchive()
{
find . -maxdepth 1 -type f | while read line; do
index="$(findExtractIndex "$line")"
if [ "$index" ]; then
echo "$line"
echo $index
return 0
fi
done
return 1
}
# Extracts a file into directory above unarchive directory.
# $1 - filename of archive
# $2 - (optional) index in extract table
function extractFile()
{
fileName="$1"
index="$2"
[ -z "$index" ] && index="$(findExtractIndex "$fileName")"
cmd="$(getExtractCmd "$curFile" "$index")"
# Perform the extract and capture the output
extractLog="$( (
cd ..
echo "Changed to directory '$(pwd)'."
eval $cmd
) 2>&1)"
extractResult=$?
# Log the output
echo -n "$extractLog" | log "Found archive '$curFile', extracting: $cmd"
# log "Found archive '$curFile', extracting: $cmd"
# echo "$extractLog" | while read l; do log "$l"; done
if [ $extractResult -eq 0 ]; then
(
[ ! -d "extracted" ] && mkdir extracted
mv "$fileName" extracted/
) 2>&1 | log "Extraction successful, deleting '$fileName'..."
return 0
else
log "Extraction failed."
return 1
fi
}
function exitHandler()
{
unlock
if [ "$cleanExit" ]; then
[ "$verbose" ] && log "Finished monitoring '$unarchiveDir' (ran for $SECONDS seconds), exiting."
else
log "Killed after $SECONDS seconds, aborting monitoring '$unarchiveDir'."
fi
}
# Process user-specified flags
while [ "`echo "$1" | grep -E -e '^-.'`" ]; do
case "$1" in
--help|-h)
printUsage
exit 0
;;
*)
printUsage
exit 1
;;
esac
shift
done
# Make sure directory is unlocked if the script is killed
trap "exitHandler" EXIT
if setupDir "$unarchiveDir"; then
cd "$unarchiveDir"
[ "$verbose" ] && log "Monitoring '$unarchiveDir' for $runTime seconds, at $checkInterval intervals..."
while [ $SECONDS -le "$runTime" ]; do
# Only continue if there are no other instances of
# this script running.
if tryLock; then
# Get the filename and index of the next archive
nextArchive="$(getNextArchive)"
# Process all archives in the current directory before sleeping
while [ "$nextArchive" ]; do
curFile=""
curIndex=""
cmd=""
echo "$nextArchive" | (
read line && curFile="$line"
read line && curIndex="$line"
cmd="$(getExtractCmd "$curFile" $curIndex)"
extractFile "$curFile" "$curIndex"
)
nextArchive="$(getNextArchive)"
done
unlock
fi
sleep "$checkInterval"
done
cleanExit="true"
fi
# Cron entry
1 * * * * auto_unarchive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment