Constantly check if file is modified bash

37,136

Solution 1

If you have inotify-tools installed (at least that's the package name on Debian) when you can do something like this:

while inotifywait -q -e modify filename >/dev/null; do
    echo "filename is changed"
    # do whatever else you need to do
done

This waits for the "modify" event to happen to the file named "filename". When that happens the inotifywait command outputs filename MODIFY (which we discard by sending the output to /dev/null) and then terminates, which causes the body of the loop to be entered.

Read the manpage for inotifywait for more possibilities.

Solution 2

Without inotifywait you can use this little script and a cron job (every minute or so):

#!/usr/bin/env bash
#
# Provides      : Check if a file is changed
# 
# Limitations   : none
# Options       : none
# Requirements  : bash, md5sum, cut
# 
# Modified      : 11|07|2014
# Author        : ItsMe
# Reply to      : n/a in public
#
# Editor        : joe
#
#####################################
#
# OK - lets work
#

# what file do we want to monitor?
# I did not include commandline options
# but its easy to catch a command line option
# and replace the defaul given here
file=/foo/bar/nattebums/bla.txt

# path to file's saved md5sum
# I did not spend much effort in naming this file
# if you ahve to test multiple files
# so just use a commandline option and use the given
# file name like: filename=$(basename "$file")
fingerprintfile=/tmp/.bla.md5savefile

# does the file exist?
if [ ! -f $file ]
    then
        echo "ERROR: $file does not exist - aborting"
    exit 1
fi

# create the md5sum from the file to check
filemd5=`md5sum $file | cut -d " " -f1`

# check the md5 and
# show an error when we check an empty file
if [ -z $filemd5 ]
    then
        echo "The file is empty - aborting"
        exit 1
    else
        # pass silent
        :
fi

# do we have allready an saved fingerprint of this file?
if [ -f $fingerprintfile ]
    then
        # yup - get the saved md5
        savedmd5=`cat $fingerprintfile`

        # check again if its empty
        if [ -z $savedmd5 ]
            then
                echo "The file is empty - aborting"
                exit 1
        fi

        #compare the saved md5 with the one we have now
        if [ "$savedmd5" = "$filemd5" ]
            then
                # pass silent
                :
            else
                echo "File has been changed"

                # this does an beep on your pc speaker (probably)
                # you get this character when you do:
                # CTRL+V CTRL+G
                # this is a bit creepy so you can use the 'beep' command
                # of your distro
                # or run some command you want to
                echo 
        fi

fi

# save the current md5
# sure you don't have to do this when the file hasn't changed
# but you know I'm lazy and it works...
echo $filemd5 > $fingerprintfile

Solution 3

Came looking for a one-liner on MacOS. Settled on the following. Compiled and added this tool to my path. This took less then 30 seconds.

$ git clone [email protected]:sschober/kqwait.git
$ cd kqwait
$ make
$ mv kqwait ~/bin
$ chmod +x ~/bin/kqwait

Next, I went to the directory in which I wished to do the watching. In this case, I wished to watch a markdown file for changes, and if changed issue a make.

$ while true; do kqwait doc/my_file.md; make; done

That's it.

Share:
37,136

Related videos on Youtube

aDoN
Author by

aDoN

Updated on September 18, 2022

Comments

  • aDoN
    aDoN over 1 year

    I have a file called file1 I want in a script, whenever there is a change in it, do something, a beep sound actually. How do I do that?

  • wurtel
    wurtel over 9 years
    Good point, I hadn't read the manpage that well :-)
  • mr.spuratic
    mr.spuratic over 9 years
    You don't strictly need while. Also note that what a human considers a "modify" might not always work: this will catch an append for example, but it will not catch an editor such as vim (file watched is renamed or swapped with a backup), nor perl -i (in-place edit) which replaces the file with a new one. Once either of those happens, inotifywait will never return. Watching an inode and watching a filename aren't quite the same thing, so it depends on the use case.
  • wurtel
    wurtel over 9 years
    You can add other events to wait for, e.g. move_self will catch renames. See the manpage for full listing of events.
  • muru
    muru over 9 years
    Use diff -q, if diff supports it.
  • Jetchisel
    Jetchisel over 9 years
    Ok let's try that: echo foo > foo.txt; echo bar > bar.txt; diff foo.txt bar.txt --> Files foo and bar differ ## (so much for being quite :))
  • muru
    muru over 9 years
    It is quieter than having every difference spelled out. -q means "report if only files differ", not how they differ. So diff -q stops comparing the moment a difference is seen, which can be very useful performance wise. See the GNU documentation, for example. If the whole point of your answer is being efficient by not using md5sum, then not using diff -q if available is defeating that point.
  • Jetchisel
    Jetchisel over 9 years
    Ok, -q "performance wise" that is good but it still prints something to stdout/stderr if the file differs from each other. I stated the ! which negate didn't I? what i'm after is the exit status of diff not being 0, ( See the GNU documentation) then take action.
  • muru
    muru over 9 years
    You're missing the point. I have no further desire to explain.
  • rogerdpack
    rogerdpack over 7 years
    as a note, worked well (if file contents change), appears to be OS X only, and you can install view brew install kqwait and you can pass multiple files to it like kqwait **/*
  • rbaleksandar
    rbaleksandar over 6 years
    entr needs to be installed or at least that's the case for Ubuntu. It should be present in most distor repositories out there though.
  • AJ Smith 'Smugger'
    AJ Smith 'Smugger' over 2 years
    I think using stat --format='%Y' $file be quicker and less resource-intensive (Depending on file size)? Also couldn't using md5sum potentially cause problems if A. The file size is large so would take more time and B. Depending on if the file is currently being written to when the command is called. I feel using stat would be the safer option.