With zsh
:
#! /bin/zsh -
files=( /opt/landing/**/*(D.:P) )
typeset -U inuse=( /proc/<->/fd/<->(D-.:P) )
cp ${files:|inuse} /opt/available/
Would copy the regular files in there which we're not seeing as currently opened on any process file descriptor (we're not looking for files that are mmapped in a process address space, but I don't expect that would be how the files are being landed there).
Here, we don't check whether the files are opened in read or write mode. Doing so would be more complicated as we'd need to also look in the /proc/*/fdinfo/*
files or parse the output of lsof
which is not straightforward.
Note that you need superuser privileges to find out about file descriptors of processes that are not yours.
Files that are being uploaded over NFS or other in-kernel network filesystem would not show up in the $inuse
list. Beware files may be renamed or reopened between each operation, so it remains a brittle approach. If you could update your landing system itself to move the files after it has finished dropping them, that would be more reliable.
**/
glob operator that stands for any level of subdirectories.
<->
any sequence of decimal digits.
(ND.:P)
/(N-.:P)
: glob qualifiers:
D
: D
otglob: also consider hidden files
.
: only regular files (not other types of files like sockets, directories, symlinks...)
-.
: same but check the type after symlink resolution
:P
: like realpath()
obtains the canonical (symlink free) absolute path of the file.
typeset -U
: makes the array elements U
nique (removes duplicates)
${files:|inuse}
: array subtraction (files that are not inuse).
- arg list too long errors if there too many files can be avoided using
zargs
or by using zsh
's builtin cp
(enabled with zmodload zsh/file
).