I'm writing a script that monitors a folder for any file creation, deletion and changing. When one of these happens, the user is notified (every 30 seconds).

Currently, I'm using for loops to go through the files in the directory and compare them to an array of files created before hand, but I cannot differentiate between new files being added and the ones that have been modified.

The code I am using is the following.

    while true; do 
        loopstart=$(date +%s)
        sleep 15

    ls -1 ~/Junk
    echo -e "\n"
    for f in ~/Junk/*; do
        if [[ ! "${files[@]}" =~ "$f" ]]; then
            echo -e "\n$f has been added"
            last_modified=$(stat -c %Z "$f")
            if [ $(($loopstart - $last_modified)) -le 15 ]; then
                echo -e "\n$f has been changed"

    for f in "${files[@]}"; do
        if [ ! -e "$f" ]; then  
            echo -e "\n$f has been deleted"



I'm aware of inotify and other systems that will provide a solution; I just need a Bash-only solution.

  • You could use stat -c %W which is the creation time/ Oct 29, 2017 at 5:37
  • Your test for whether a file is new might not work right.   Try creating a file called credit, then start the watcher, then create a file called red and see what happens. Oct 29, 2017 at 5:47
  • 2
    Some alternative ideas... Instead of relying on just filenames consider incorporating inode numbers which are unique for each file. These numbers will stay with a file even if it is renamed. Retrieve inode number with stat -c %i filename. To determine if a file's content has changed you might use checksums instead of modification times. One way to get a checksum is cksum filename.
    – B Layer
    Oct 29, 2017 at 8:50
  • What about symlinks, hardlinks, and file names beginning with a dot, can all that be ignored? Oct 29, 2017 at 9:59
  • You've asked for a "bash-only solution". Do you really intend to discount grep, find, and other external tools? If not, please could you clarify why inotify-based answers are no use to you. Thanks Oct 29, 2017 at 10:59

3 Answers 3


You can use the output of

find . -mindepth 1 -maxdepth 1 -type f -printf '%C@ %T@ ' -ls

which is a lot faster than calling stat (especially several times) per file. The combination of -printf and -ls has a better handling of strange file names. If you can be sure such ones will not occur then you can use

-printf '%i %C@ %T@ %P'


The inode (as mentioned in the comments) identifies the object. The ctime and mtime tell you whether the file data or metadata has been written (does not tell you whether it has really changed, though). You should write these data to arrays in a

find ... | while IFS= read ctime mtime inode dummy1 ... dummy9 rest; do ...



The issue is the very end of the script. I'll repost your script with the correction.

change "start_watcher" to "start" since you are trying to run the start function.


Try to use Auditd


For monitoring a directory, you need

auditctl -w /path/to/dir -p wa -k CHANGED_ON_DIR

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .