I'm a bit late to the party here, I'm not sure exactly what's going wrong.
It seems to me that you aught to have two lists of files.
in your infinite while loop:
- use find to get a list of current files/directories
- check to see if there is a previous-list:
- if a previous-list exists, grep through the current list and output any lines that are NOT in the previous list.
- copy the current list to previous-list
- sleep for 30 seconds, or however long.
The first time through your loop, it will create the "current" list.
- The "previous" list won't exist. so the grep will just be skipped
The "current" list is copied to the "previous" list - at this point the "previous" list exists and is the same as the "current" list.
Then the process sleeps.
On each wake-up after that:
- it will use find to get an up to date "current" list
- the lists will be checked against each other for new entries and new entries will be output
- the current list is copied to the "previous" list
- the process sleeps again.
As you're using an infinite loop and temporary files in the /tmp file-sytem, I'd recommend setting up a
trap
for
SIGINT
(ctrl + c) which will delete the temporary files and then exit.
That way, when you kill your script (via ctrl+c, or using
kill -2 {pid}
to send the SIGINT signal to the process - where {pid} is the PID of the running process.) the script will clean up
/tmp
before exiting.
Also - as you're using
/tmp
- you may as well create a directory in /tmp using
mktemp -d
.
I don't have anything better to do right now, here's my attempt:
Bash:
#!/usr/bin/env bash
# Display an error message and show usage information if we experience an error
die()
{
echo -e "ERROR: $1"
echo -e "Usage: $0 /path/to/directory"
echo -e "Expects a path to an existing directory as a parameter. The directory will be monitored until you press ctrl+c"
echo -e "Results will be echoed to the screen AND written out to ~/newFSObjectLog\n"
}
# Check the parameters we received
# We want ONE parameter and it MUST be a path to a valid directory
if [ $# -ne 1 ]; then
die "Wrong number of parameters."
exit 1
elif [ ! -d "$1" ]; then
die "Directory \"$1\" does not exist,"
exit 1
fi
# The parameter we received is the directory we want to monitor
watchDir="$1"
# Create a temporary directory in /tmp
tempPath="$(mktemp -d)"
# Set up variables to hold the path/filenames for the two directory listings
currentList="${tempPath}/currentList"
previousList="${tempPath}/previousList"
# Cleanup function to remove temporary files
cleanup()
{
echo -e "\nRemoving temporary directory and files at ${tempPath}\n"
rm -r "$tempPath"
}
# Trap to capture SIGINT (ctrl + c / keyboard interrupt signal) and will delete the temporary directory and exit
trap -- 'cleanup;exit' SIGINT
# Main loop
while true; do
find "$watchDir" -type f -or -type d > "$currentList"
# If we have a previous list, output any lines in currentList that AREN'T in previousList
if [ -f "$previousList" ]; then
while read -r line; do
grep -qw "$line" "$previousList" || echo -e "- $line" | tee -a ~/newFSObjectLog
done < "$currentList"
fi
cp "$currentList" "$previousList"
sleep 60
done
There we go. I think that covers all of the bases!
That takes a path to a directory as a parameter. I've added some checks to ensure that the script only receives a single parameter and that it is a path to a valid directory.
If the incorrect number of parameters are passed, or the parameter IS NOT a valid path, the
die
function is used to display an error message, plus some usage information. And then the script exits with error code 1 (General error).
If the parameter
is a valid path:
- we create a temporary directory in
/tmp
using mktemp -d
.
- We set up the paths/filenames for the two lists we'll be manipulating.
- We have a cleanup function, which will remove the temporary directory (and the files it contains)
- We set up a trap for the
SIGINT
signal, which calls the cleanup
function and exits.
That way, when you press ctrl+c to kill the script, the script will clean up after itself and remove the temporary directory.
- Then we have our main, infinite
while
loop, which operates as described in the earlier part of this post.
A few lines of interest in the main loop are the
while read
loop, where the
currentList
is redirected into the
read
loop via the input redirection operator
<
:
Bash:
while read line; do
....
done < "$currentList"
In that bit of code, the entire file is being redirected, line by line into the
while read
loop.
Another noteworthy bit of code is the line that happens inside the
while read
loop:
Bash:
grep -qw "$line" "$previousList" || echo -e "- $line" | tee -a ~/newFSObjectLog
The first part:
Bash:
grep -qw "$line" "$previousList"
Uses
grep
to see if the current
$line
from
currentList
matches any lines in
previousList
. The
-w
option ensures that the entire
$line
exactly matches a line in
previousList
.
The
||
after the
grep
command is a conditional boolean OR operator. If the
grep
command fails to find a match, the code after the
||
is executed. And in this case, it echoes the current
$line
read from
currentList
and pipes the output to
tee
, which in turn appends the output to a log-file in the users home directory.
So if the
grep
command succeeds - it means that the pattern in
$line
already exists in
currentList
and the code after the
||
does NOT get executed.
Whereas if the grep command fails, the pattern
$line
DOES NOT exist in
currentList
, so therefore this is a new file/directory that has appeared since the last time we checked the
watchDir
directory.
Because the
grep
command failed, the code to the right of the
||
operator is ran and the new file/directory is logged.
I hope this helps you with your scripting journey!