0

and thanks in advance for any advice.

I'm having trouble finding an answer to my question elsewhere. I've been working on a script that will watch a directory, and then move files to various other directories based on certain criteria. Here's what I've got so far:

cd `dirname $0`/watch
  while true
  do
    inotifywait -e moved_to ../watch --format "%f" | while read FILE
    do
      if $(echo "$FILE" | grep -q ".jpg"); then
          cp "./$FILE" "../images/"
      elif $(echo "$FILE" | grep -q ".mp4"); then
          cp "./$FILE" "../videos/"
      elif $(echo "$FILE" | grep -q ".mp3"); then
          cp "./$FILE" "../audio/"
      else
          cp "./$FILE" "../other/"
    fi
    done
  done

This script works as it should if one file at a time is moved into ./watch, but if multiple files are moved, only the first of them gets moved from ./watch to the corresponding directory. Here's another idea I have, but am unsure how this would handle problems such as trying to sort/move incomplete files:

while true
do
inotifywait -e moved_to `dirname $0`/watch && /bin/bash `dirname $0`/autotorrent.sh
done

which will launch the following script when files are added:

cd `dirname $0`/watch
for i in *; do
    if $(echo "$FILE" | grep -q ".jpg"); then
        cp "./$FILE" "../images/"
    elif $(echo "$FILE" | grep -q ".mp4"); then
        cp "./$FILE" "../videos/"
    elif $(echo "$FILE" | grep -q ".mp3"); then
        cp "./$FILE" "../audio/"
    else
        cp "./$FILE" "../other/"
    fi
done

I'm just not sure how best to handle moving multiple files which may or may not take considerable time to copy. I've got several ideas, but none of them really seem to be the robust solution I'm looking for.

Thanks again to anyone who has some advice for me

  • Quick suggestion: your grep commands really should be grep -qF ".mp4" or, even better, grep -q '\.mp4$' etc. The dot in regular expressions matches any character, so you really should escape it to make it literal. Otherwise e.g. stuff like foobarmp4 will be matched. – kos Dec 5 '15 at 4:30
0

Since your files could be Large, the cp takes non-zero time. During this time, you probably miss notifications. Try tossing all the cp commands into the background by appending a & to each. That will get you back to the inotifywait quicker.

Also, you could eliminate a bunch of calls to grep by doing:

    j=${i##*.}
    case "$j" in 
        jpg) cp $i ../images/ & ;;
        mp4) cp $i ../videos/ & ;;
        mp3) cp $i ../audio/ & ;;
        *) cp $i ../other/& ;;
    esac

Although I don't see why you want to keep a copy of each file both directories, why not use mv instead of cp?

@zpawwn: On further man inotifywait reading, I found --monitor, so, your script should be:

cd `dirname $0`/watch
inotifywait -e moved_to ../watch --format "%f" --monitor | while read FILE
do
    j="${FILE##*.}"
        case "$j" in 
            jpg) mv "$FILE" ../images/ & ;;
            mp4) mv "$FILE" ../videos/ & ;;
            mp3) mv "$FILE" ../audio/ & ;;
            *) mv "$FILE" ../other/& ;;
        esac
 done

Let inotifywait manage the file event queueing, and spit out filenames as it notices them. The old way had inotifywait finding ONE new file and exiting, letting your cp stuff run, then restart watching. The other files (that arrived at the same time) are no longer new (they were there when the 2nd inotifywait started).

  • I like that method for eliminating the grep calls. I also had forgotten to change the cp commands to mv when posting - that was actually something I had changed just for testing the script, and plan to use mv once everything is working properly – Curtis Everingham Dec 6 '15 at 0:34
  • I have modified the code to work pretty much exactly how you illustrated it here, the main difference is right now i've replaced the cp commands inside of the case statement with an echo "SUCCESS" message, and I'm getting inconsistent behavior. If I copy over a directory of 13 files, I get anywhere from 1 to 13 "SUCCESS" lines printed – Curtis Everingham Dec 6 '15 at 0:41
  • Eliminate the outer while true loop, read man inotifywait and use the --monitor switch. What you're doing is inefficient. – waltinator Dec 6 '15 at 0:50

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.