10

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?

15

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.

3
  • Good point, I hadn't read the manpage that well :-)
    – wurtel
    Nov 6 '14 at 15:01
  • 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. Nov 7 '14 at 12:48
  • 1
    You can add other events to wait for, e.g. move_self will catch renames. See the manpage for full listing of events.
    – wurtel
    Nov 7 '14 at 12:50
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
2

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 git@github.com: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.

1
  • 1
    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 **/*
    – rogerdpack
    Oct 11 '16 at 17:53
0

You probably don't need to compare md5sum if you have the diff utility available.

if ! diff "$file1" "$file2" >/dev/null 2>&1; then
  echo "$file1 and $file2 does not match" >&2
  ## INSERT-YOUR-COMMAND/SCRIPT-HERE
  ## e.g. cp "$file1" "$file2"
fi

the ! negates e.g. true if the statement is false

Caveat is you need the original file to compare with diff which (imo) the same as what md5sum script is doing above.

5
  • Use diff -q, if diff supports it.
    – muru
    Jan 13 '15 at 4:37
  • 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 :))
    – Jetchisel
    Jan 13 '15 at 5:27
  • 1
    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.
    – muru
    Jan 13 '15 at 5:32
  • 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.
    – Jetchisel
    Jan 13 '15 at 5:40
  • You're missing the point. I have no further desire to explain.
    – muru
    Jan 13 '15 at 5:41
0

You can try entr command-line tool, e.g.

$ ls file1 | entr beep
1
  • 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. Nov 16 '17 at 9:32
0

if you are checking changes in a git repo, you can use:

#!/usr/bin/env bash

diff="$(git diff | egrep some_file_name_or_file_path | cat)"

if [[ -n "$diff" ]] ; then
    echo "==== Found changes: ===="
    echo "diff: $diff"
    exit 1
else
    echo 'Code is not changed'
fi

0
Done in 2 steps Tested and worked fine in both scenarios

a. cp orginalfile fileneedto_be_changed'(Need to do only one Time)

orginalfile=====>which supposed to be changed

b.

differencecount=`awk 'NR==FNR{a[$0];next}!($0 in a){print $0}' orginalfile fileneedto_be_changed|wc -l`

if [ $differencecount -eq  0 ]
then
echo "NO changes in file"
else
echo "Noted there is changes in file"
fi

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.