-1

I'm trying to setup an inotifywait script to do this:

  • Step 1: Directory is created, files are placed in it, which triggers inotifywatch to fire which does step 2
  • Step 2: After 30 minutes, the directory moved and a symlink is created back to the old root directory

This is what I have so far but it's not quite working. It's kind of hacked together from different examples I've found online.

inotify.sh:

#!/bin/sh

cd ~/automove/old/
inotifywait -m -e close_write --format %w%f . | while IFS= read -r file; do
  echo $file
  sleep 15
  sh ~/automove/move.sh "$file" ~/automove/new/
done

move.sh:

#!/bin/sh
original="$1" target="$2"
if [ -d "$target" ]; then
  target="$target/${original##*/}"
fi
mv -- "$original" "$target"
ln -s -- "$target" "$original"

My problems with this are the following:

  • Directories that have 'apostrophes' get mangled.
  • It seems as though inotifywait will get trigged on the new symlinks, creating an endless loop that goes crazy.
  • If a directory triggers the inotifywait and then it sleeps for 15 seconds (which I set as a test, in practice I want 30 minutes) and then another directory shows up before the original 15 seconds is up, it won't even start the second 15 second sleep until the first one is done.

I need the sleep to trigger separately for each inotifywait match. Can anyone tell me how I can modify this to work the way I need?

stab
  • 9
  • 1

1 Answers1

0

Starting your script with #!/bin/bash instead of #!bin/sh would make sure you are really using bash (some of your constructs are bash-specific I think). You might want to add -ue to make sure that your problem is not caused by a silently failing variable reference or command.

--

"Mangled" directories

Could you please be more specific as to what happens?

--

"Separate 15 second wait"

You pipe the output of inotifywait to a while loop. Each side of the pipe is a separate process. If I understand correctly, you want the loop to continue to the next iteration without waiting, while separately waiting for 15 seconds before performing the rest of the statements.

To do that, you need to create an additional process to perform the sleep and the following statements. Enclose the statements inside of the loop inside brackets, and add & after the closing bracket, like so :

{
  echo $file
  sleep 15
  sh ~/automove/move.sh "$file" ~/automove/new/
} &

You could optionally put these statements inside a function and call that function from inside the loop, followed by the same & character (which executes the statement in a separate process executing in the background).

You may want to add a wait statement at the end of your script so that it waits for all children processes to end before actually handing back control to the process that launched it.

--

Endless loop : I have not tested, but inotifywait probably triggers on your symbolic link being created. You may want to have your loop look like this :

do
  if
    ! [ -d "$file" ] || [ -L "$file" ]
  then
    continue
  fi
  (followed by the code suggested above...)
done

This code would bypass the rest of the code inside the loop and skip to the next iteration when the target file is not a directory.

Note : [ -d "$file" ] seems to return 0 (true) when testing a symbolic link to a directory, so the test I suggest makes sure that the file is a directory and is not a symbolic link.

--

Please note I have not tested your code or the one I suggest.

I hope this helps!

Fred
  • 6,590
  • 9
  • 20