I need to track folder access time, and want to know what changes are made to it.
How do I trigger those events? Is there a way to run a specific .sh file when the folder is opened?
I assume you need to know the (clock-) time the folder is opened in e.g. nautilus, not the time it takes to access the folder.
You can get the window list from the command
wmctrl -l, and see if the folder's name occurs in the list. The loop to check would however take at least a split second to notice the folder is opened.
wmctrl to be installed:
sudo apt-get install wmctrl
In the example below, the script runs a command when a folder is accessed for the first time, and exits.
How to use:
"<command_to_run>"by your command (between quotes)
Run it either with the command:
python3 </path/to/script> <foldername_without_path>
or, if you made it executable:
#!/usr/bin/env python3 import subprocess import sys #--- replace "<command_to_run>" with your command (between quotes): command = "<command_to_run>" #--- foldername = sys.argv while True: try: test = subprocess.check_output(["wmctrl", "-l"]).decode("utf-8") except subprocess.CalledProcessError: pass if foldername in test: subprocess.call(["/bin/bash", "-c", command]) break
You can however make it work "all-in-one", so you do not need another script. The script below creates a file in your $HOME directory with the time your folder was accessed.:
#!/usr/bin/env python3 import subprocess import sys import os import time home = os.environ["HOME"] foldername = sys.argv #--- the path your file is saved to (change if you want to, but use full paths) path = home #--- while True: try: test = subprocess.check_output(["wmctrl", "-l"]).decode("utf-8") except subprocess.CalledProcessError: pass if foldername in test: with open(path+"/time_data.txt", "a") as out: out.write("the folder "+foldername+" was opened "+time.ctime()+"\n") break
Place a dot before the filename to make it a hidden file (press Ctrl+H to toggle visability):
If you want that, change:
with open(path+"/time_data.txt", "a") as out:
with open(path+"/.time_data.txt", "a") as out:
(Mind the indent!)
From your comments, and the discussion in chat, I understand that you are actually looking for a tool to log access to a folder (e.g. by nautilus) and changes in the contents of it.
As an extra option, a comprehensive log script that records in two different threads:
These events are logged in two different files, because the logs have different refresh times. Real-time "recording" of what happens to a large directory with a lot of subdirectories is not something you would want to be done every 5 seconds or so. The consequence is that:
the directory log (adding/removing files) has an accuracy 10 minutes. Events will be reported within 10 minutes after taking place, with a time stamp accuracy of 10 minutes.
I tested it on a (network-) directory of ~800 GB. If your directory is much smaller, the directory log- cycle can be (much) smaller as well. I tested it for example on a 20 GB directory, with a (directory log) cycle of 10 seconds.
Example output access_log.txt:
---------------Thu Feb 19 21:01:09 2015--------------- folder opened ---------------Thu Feb 19 21:01:27 2015--------------- folder closed
Example output directory_log.txt:
---------------Thu Feb 19 21:14:24 2015--------------- + /home/jacob/Afbeeldingen/Downloads/2023.pdf - /home/jacob/Afbeeldingen/Downloads/History-journal - /home/jacob/Afbeeldingen/Downloads/google-earth-stable_current_i386.deb
Set it up like the scripts above with an important difference:
The command to run it then is:
#!/usr/bin/env python3 import subprocess import os import time import difflib from threading import Thread home = os.environ["HOME"] # The folder to watch: folder = "/home/jacob/Afbeeldingen" # the path your log files are saved to (change if you want to, but use full paths): path = home #--- for f in os.listdir(path): if f.startswith("dr_check_"): os.remove(path+"/"+f) dr_data = path+"/directory_log.txt" access_data = path+"/access_log.txt" for f in [dr_data, access_data]: if not os.path.exists(f): subprocess.Popen(["touch", f]) foldername = folder.split("/")[-1] def check_windowlist(foldername): while True: try: if foldername in subprocess.check_output(["wmctrl", "-l"]).decode("utf-8"): return "folder opened\n" else: return "folder closed\n" break except subprocess.CalledProcessError: pass def check_directory(directory, outfile): with open(outfile, "wt") as out: for root, dirs, files in os.walk(directory): for f in files: out.write(root+"/"+f+"\n") def run_accesscheck(): while True: ch1 = check_windowlist(foldername) time.sleep(0.5) ch2 = check_windowlist(foldername) if ch1 != ch2: with open(access_data, "a") as out: out.write("-"*15+time.ctime()+"-"*15+"\n"+ch2+"\n") def run_directorycheck(): last = 1; outfile_name = "dr_check_"; last_outfile = "" while True: outfile = path+"/"+outfile_name+str(last)+".txt" check_directory(folder, outfile) if last != 1: changes =  diff = difflib.ndiff( open(last_outfile).readlines(), open(outfile).readlines() ) for item in diff: if item.startswith("-") or item.startswith("+"): changes.append(item) if len(changes) > 0: with open(dr_data, "a") as out: out.write("-"*15+time.ctime()+"-"*15+"\n") for it in sorted(changes): out.write(it) out.write("\n") os.remove(last_outfile) last_outfile = outfile; last = last+1 time.sleep(600) Thread(target = run_directorycheck).start() Thread(target = run_accesscheck).start()
If you want to use Bash instead Python:
#!/bin/bash folder=$1 while true; do command=$(wmctrl -l | grep -o "$folder") if [[ "$folder" == "$command" ]]; then ./myscript.sh break; fi done
I changed a script so you can run it with the following command:
bash folderwatch.sh BackupSSD
Also, you can make a script executable so you can use it without sh or bash, because the shell is defined in the first line of the script, for example:
chmod u+x folderwatch.sh ./folderwatch.sh BackupSSD
sudo apt-get incron to install the "inotify cron" system
echo $USER | sudo tee --append /etc/incron.allow to allow you to play the game.
icrontab -e to create an event to watch. It opens
Enter your heart's desire. e.g.,
/home/nodak/watched_dir IN_ACCESS /home/nodak/bin/personal.sh
Save and test.
More information from http://manpages.ubuntu.com/manpages/saucy/man5/incrontab.5.html
While it is simple, and deceptively so, the syntax for complicated manoeuvres is not quite the same as regular bash, c.f., https://stackoverflow.com/questions/23706194/using-zenity-in-a-root-incron-job-to-display-message-to-currently-logged-in-user