J4N
J4N

Reputation: 20717

Shell: Wait that a file has been copied

I've a shell script which list files of a folder and then do an action on them(print into a PDF), but very often I get a blank PDF. If I remove the generated PDF, the new PDF is always correctly generated.

I've the impression that is because my script started to print BEFORE the file has been fully copied(the copy is made through the OS explorer, with a save as, or just copy-paste).

It's absolutely not me which manage when someone add a new file, the copy comes from users which uses a network share.

so is there a way to have something like this?

for inputFile in `ls -l $SearchPattern | grep ^- | awk '{print $9}'`
do
   //CHECK_THAT_THE_FILE_HAS_ALREADY_BEEN_FULLY_SAVED_ONCE 
   //DO_MY_PRINT_HERE
done

Upvotes: 1

Views: 5858

Answers (4)

J4N
J4N

Reputation: 20717

I ended by using

for inputFile in `find $SearchPattern2 -maxdepth 1 -type f -cmin +1 -iname "*.pdf"`

the -cmin +1 indicate to find, that is has to list only file with the modification time >1min ago.

It's not 100% safe, but it will handle all my case with a lot of margin.

I didn't find how to do this in seconds

Upvotes: 1

marcelog
marcelog

Reputation: 7180

As someone pointed out, using the file modification time might be useful. I've quickly done this script that might be useful. It will wait until 5 seconds have passed since the last modification time of a given file:

#!/bin/bash

function getTimeFromLastChange() {
    file=${1}
    let lastAccess=$(stat --format=%Y ${file})
    let now=$(date +%s)
    let timePassed=$((now - lastAccess))
    echo ${timePassed}
}

file=./test
while [ true ]; do
    let lastChange=$(getTimeFromLastChange ${file})
    if [ "${lastChange}" -lt 5 ]; then
        echo "waiting"
        sleep 1
    else
        echo "done"
        exit
    fi
done

echo ${timePassed}

The key here is the "getTimeFromLastChange" function that uses stat (http://linux.die.net/man/1/stat) to get the last modification time for the given file in seconds since the unix epoch time. Then, it will get the current time using date (http://linux.die.net/man/1/date) (again, in seconds since the unix epoch time), substract them, and figure the total amount of seconds since the last modification time.

The main loop will wait until some "safe" amount of seconds have passed by. So you can try tunning this parameter and print the files that were written/modified some N amonut of seconds ago.

A sample run:

marcelog@host ~ $ touch ./test
marcelog@host ~ $ ./try.sh
waiting
waiting
waiting
done

It's not 100% safe. But I think it's worth giving it a try.

Hope it helps!

Upvotes: 2

larsks
larsks

Reputation: 311605

If you are running under Linux and the filesystem is local to your server, then you can use the inotify subsystem to wait until the file is closed and then trigger an action. The inotify-tools package includes the inotifywait program, which exposes inotify functionality to shell scripts.

For example, you can watch for the close_write event in a directory like this:

inotifywait -e close_write -m /path/to/directory

With this command running, doing this:

echo hello > /path/to/directory/file

Will generate output like this:

/path/to/directory/ CLOSE_WRITE,CLOSE hello

So there you have the directory and filename that generated the event. In a shell script you can pipe this into a loop:

inotifywait -e close_write -m /path/to/directory | while read dir flags file; do
  ...do something with the file...
done

Upvotes: 3

blackcoffeerider
blackcoffeerider

Reputation: 52

you should check the modification time of the data and have a threshold on that. There is no other (easy) way to see if there is no more operation pending on the file.

so you should use

ls -l -t

in you find statement above and pipe that through a "sort" accordingly to you time threshhold.

Greetings

Upvotes: 0

Related Questions