2

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?

  • search up incron. not sure if it can handle directories, though. – strugee Feb 17 '15 at 7:13
3

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.

Using the window list

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.

You'd have 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:

  • Paste the script into an empty file
  • Save it as access_time.py
  • Change in the head section of the script "<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:

    </path/to/access_time.py> <foldername_without_path>
    
#!/usr/bin/env python3
import subprocess
import sys
#--- replace "<command_to_run>" with your command (between quotes):
command = "<command_to_run>"
#---
foldername = sys.argv[1]
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

Edit

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[1]

#--- 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
  • Use it just like the first option (but obviously you don't need to set the command)
  • 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:
    

    into:

    with open(path+"/.time_data.txt", "a") as out:
    

    (Mind the indent!)

Edit 2

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:

  • All occasions the folder was accessed by e.g. nautilus, logged in a file access_log.txt
  • All occasions that the folder's window was closed, also logged in access_log.txt
  • All files that where either added to (recursively), or removed from the directory, logged into a file directory_log.txt

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 access log has (as I set it) an accuracy of 0.5 seconds
  • 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

The script:

  • Set it up like the scripts above with an important difference:

    • instead of using the foldername as an argument, set the complete path+the foldername in the head of the script (see example in the script)
  • The command to run it then is:

    python3 /path/to/script.py
    
#!/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()
  • When I run this script an error occurs like this, ~/Documents$ python3 folderWatch.py BackupSSD /bin/bash: -c: line 0: syntax error near unexpected token newline' /bin/bash: -c: line 0: <some_command>' – tvshajeer Feb 18 '15 at 4:49
  • 1
    @tvshajeer The some command is supposed to be replaced by the path to your script, or the command you wish to run. – muru Feb 18 '15 at 5:31
  • @tvshajeer like muru mentioned, the "<some_command>" is not a real command :). What is the command or script you would like to run?. – Jacob Vlijm Feb 18 '15 at 6:44
  • @tvshajeer Edited my answer into a "all in one" option, you do not need to change anything in this one. Another question: would the script need to record only the first occurrence of accessing the folder, or all / last? would you need (want) to run it on startup? – Jacob Vlijm Feb 18 '15 at 7:23
  • @Jacob Vlijm the script should record all access to the folder or folder content changes – tvshajeer Feb 19 '15 at 7:23
1

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

Edit:

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
  • @muru @Panta I ran this sh script using ~/Documents$ sh folderwatch.sh BackupSSD then keep on generating this error folderwatch.sh: 6: folderwatch.sh: [[: not found – tvshajeer Feb 18 '15 at 5:24
  • @tvshajeer Instead sh use bash folderwatch.sh. Also foldername replace with a name of folder you want to watch. – Panta Feb 18 '15 at 6:45
  • I tried your edited code and it generates an error folderwatch.sh: line 8: ./myscript.sh: No such file or directory – tvshajeer Feb 19 '15 at 7:40
  • @tvshajeer myscript.sh replace with the command you wish to run when the folder is opened. – Panta Feb 19 '15 at 12:58
0

sudo apt-get incron to install the "inotify cron" system

http://inotify.aiken.cz/?section=incron&page=about&lang=en

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 nano.

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.