Monitoring folder for file changes

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
1
down vote

favorite












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.



start()

files=(~/Junk/*)
while true; do
loopstart=$(date +%s)
watcher
sleep 15
done


watcher()

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

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

files=(~/Junk/*)


start_watcher


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







share|improve this question






















  • You could use stat -c %W which is the creation time/
    – Ralph Rönnquist
    Oct 29 '17 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.
    – G-Man
    Oct 29 '17 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 '17 at 8:50











  • What about symlinks, hardlinks, and file names beginning with a dot, can all that be ignored?
    – Hauke Laging
    Oct 29 '17 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
    – roaima
    Oct 29 '17 at 10:59














up vote
1
down vote

favorite












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.



start()

files=(~/Junk/*)
while true; do
loopstart=$(date +%s)
watcher
sleep 15
done


watcher()

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

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

files=(~/Junk/*)


start_watcher


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







share|improve this question






















  • You could use stat -c %W which is the creation time/
    – Ralph Rönnquist
    Oct 29 '17 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.
    – G-Man
    Oct 29 '17 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 '17 at 8:50











  • What about symlinks, hardlinks, and file names beginning with a dot, can all that be ignored?
    – Hauke Laging
    Oct 29 '17 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
    – roaima
    Oct 29 '17 at 10:59












up vote
1
down vote

favorite









up vote
1
down vote

favorite











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.



start()

files=(~/Junk/*)
while true; do
loopstart=$(date +%s)
watcher
sleep 15
done


watcher()

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

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

files=(~/Junk/*)


start_watcher


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







share|improve this question














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.



start()

files=(~/Junk/*)
while true; do
loopstart=$(date +%s)
watcher
sleep 15
done


watcher()

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

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

files=(~/Junk/*)


start_watcher


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









share|improve this question













share|improve this question




share|improve this question








edited Oct 29 '17 at 6:27









kiamlaluno

362220




362220










asked Oct 29 '17 at 5:00









Alphala7

61




61











  • You could use stat -c %W which is the creation time/
    – Ralph Rönnquist
    Oct 29 '17 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.
    – G-Man
    Oct 29 '17 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 '17 at 8:50











  • What about symlinks, hardlinks, and file names beginning with a dot, can all that be ignored?
    – Hauke Laging
    Oct 29 '17 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
    – roaima
    Oct 29 '17 at 10:59
















  • You could use stat -c %W which is the creation time/
    – Ralph Rönnquist
    Oct 29 '17 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.
    – G-Man
    Oct 29 '17 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 '17 at 8:50











  • What about symlinks, hardlinks, and file names beginning with a dot, can all that be ignored?
    – Hauke Laging
    Oct 29 '17 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
    – roaima
    Oct 29 '17 at 10:59















You could use stat -c %W which is the creation time/
– Ralph Rönnquist
Oct 29 '17 at 5:37





You could use stat -c %W which is the creation time/
– Ralph Rönnquist
Oct 29 '17 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.
– G-Man
Oct 29 '17 at 5:47




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.
– G-Man
Oct 29 '17 at 5:47




2




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 '17 at 8:50





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 '17 at 8:50













What about symlinks, hardlinks, and file names beginning with a dot, can all that be ignored?
– Hauke Laging
Oct 29 '17 at 9:59




What about symlinks, hardlinks, and file names beginning with a dot, can all that be ignored?
– Hauke Laging
Oct 29 '17 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
– roaima
Oct 29 '17 at 10: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
– roaima
Oct 29 '17 at 10:59










3 Answers
3






active

oldest

votes

















up vote
1
down vote













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'


instead.



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


loop.






share|improve this answer



























    up vote
    0
    down vote













    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.






    share|improve this answer



























      up vote
      0
      down vote













      Try to use Auditd



      https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/security_guide/chap-system_auditing


      For monitoring a directory, you need



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





      share|improve this answer




















        Your Answer







        StackExchange.ready(function()
        var channelOptions =
        tags: "".split(" "),
        id: "106"
        ;
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function()
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled)
        StackExchange.using("snippets", function()
        createEditor();
        );

        else
        createEditor();

        );

        function createEditor()
        StackExchange.prepareEditor(
        heartbeatType: 'answer',
        convertImagesToLinks: false,
        noModals: false,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: null,
        bindNavPrevention: true,
        postfix: "",
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        );



        );













         

        draft saved


        draft discarded


















        StackExchange.ready(
        function ()
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f401155%2fmonitoring-folder-for-file-changes%23new-answer', 'question_page');

        );

        Post as a guest






























        3 Answers
        3






        active

        oldest

        votes








        3 Answers
        3






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes








        up vote
        1
        down vote













        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'


        instead.



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


        loop.






        share|improve this answer
























          up vote
          1
          down vote













          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'


          instead.



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


          loop.






          share|improve this answer






















            up vote
            1
            down vote










            up vote
            1
            down vote









            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'


            instead.



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


            loop.






            share|improve this answer












            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'


            instead.



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


            loop.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Oct 29 '17 at 10:49









            Hauke Laging

            53.6k1282130




            53.6k1282130






















                up vote
                0
                down vote













                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.






                share|improve this answer
























                  up vote
                  0
                  down vote













                  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.






                  share|improve this answer






















                    up vote
                    0
                    down vote










                    up vote
                    0
                    down vote









                    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.






                    share|improve this answer












                    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.







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Feb 12 at 19:03









                    Nkiruka Christian

                    1




                    1




















                        up vote
                        0
                        down vote













                        Try to use Auditd



                        https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/security_guide/chap-system_auditing


                        For monitoring a directory, you need



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





                        share|improve this answer
























                          up vote
                          0
                          down vote













                          Try to use Auditd



                          https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/security_guide/chap-system_auditing


                          For monitoring a directory, you need



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





                          share|improve this answer






















                            up vote
                            0
                            down vote










                            up vote
                            0
                            down vote









                            Try to use Auditd



                            https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/security_guide/chap-system_auditing


                            For monitoring a directory, you need



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





                            share|improve this answer












                            Try to use Auditd



                            https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/security_guide/chap-system_auditing


                            For monitoring a directory, you need



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






                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Feb 12 at 19:08









                            CorTheZ

                            1272




                            1272



























                                 

                                draft saved


                                draft discarded















































                                 


                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function ()
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f401155%2fmonitoring-folder-for-file-changes%23new-answer', 'question_page');

                                );

                                Post as a guest













































































                                Popular posts from this blog

                                How to check contact read email or not when send email to Individual?

                                Displaying single band from multi-band raster using QGIS

                                How many registers does an x86_64 CPU actually have?