Some comments over your code (assuming it's meant to be in sh
syntax):
cd /apps/common/bau/base/
You're not checking the exit status of cd
, so if it fails, you'll carry on running the rest of the script in the current working directory, whatever it is.
for file in `cat /tmp/fmxfileslist`
That uses split+glob on top of the deprecated `...`
form of command substitution, while it looks like you want to iterate over the lines of the file for which the syntax would be:
while IFS= read -r file <&3; do
...
done 3< /tmp/fmxfileslist
(or should it be /tmp/fmxfile
instead)?
Also note that using files with fixed names in world-writable directories such as /tmp
is bad practice from a security standpoint.
Also, none of the path in your sample list are relative, so does it matter what the current working directory is? Or should the list be:
fmx/eng/hint.fmx
pll/case.pll
plx/eng/case.plx
instead? Or should the leading /
be stripped or a .
inserted before it?
do
if [ -f $file ]
That's using split+glob again over the expansion of $file
, which doesn't make sense. You likely meant [ -f "$file" ]
if the intention was to check that the file exists, is accessible to you and can be determined to be regular (not directory, fifo, device, socket...) after symlink resolution.
then
echo "File '${file}' found in $(pwd) path and created on $(date +%D)."
$(pwd)
this time using the modern form of command substitution can be written $PWD
in POSIX shells. date +%D
prints the current date. To print the last modification time of $file
, assuming GNU date
, you can use the -r
option. %D
gives dates in mm/dd/yy
format which is very ambiguous and doesn't give any information of time nor timezone. $(date -r "$file" +%FT%T%z || echo UNKNOWN)
.
Also note that echo
can't be used for arbitrary data. Use printf '%s\n' "..."
instead.
if [ $(find $file -mmin -5 -type f) ="true" ];
Again, using split+glob on both $file
and the output of find
. You're also missing a space after the =
so the [
command won't see a =
comparison operator argument but a bogus =true
one.
Also, as find
will print the file paths that it finds, it will only ever print true
if $file
is true
(true
followed by any number of newline characters would also work as trailing newlines are stripped by command substitution, but as you're reading your fmxfileslist
file one line at a time, that cannot happen; IOW your fmxfileslist
file cannot include arbitrary file names).
Also note that find
will choke on file names starting with -
(also on !
, (
...).
And -type f
returns false for symlinks to regular files while the [ -f "$file" ]
above would return true. You'd need the GNU specific -xtype f
to get consistency between the two or use -L
to also check the modification time of the target of the symlink (as date -r
also does), so, assuming GNU find
4.9 or newer:
if [ "$(
printf '%s\0' "$file" | find -L -files0-from - -prune -type f -mmin -5 -printf true)" = true ]
then
printf '%s\n' "$file is found to be regular after symlink resolution and has been last modified within the last 5 minutes or in the future"
fi
Here passing the file path NUL-delimited on find
's stdin (which it gets from there with -files0-from -
, the part needing 4.9 or newer), instead of as argument to avoid the choking issue mentioned above.¹
then
cp -a $file /tmp/basefmxfiles
Again, non-sensical split+glob, and you're also missing the --
option delimiter. If /tmp/basefmxfiles
didn't exist as a directory beforehand, that would create it as a copy of $file
instead, so it's a good habit to append a /
to the end of the target directory to avoid that (or here since you're already using GNUisms, use GNU cp
's -t
option):
cp -a -- "$file" /tmp/basefmxfiles/
cp -at /tmp/basefmxfiles -- "$file"
ls -lrt | grep /tmp/basefmxfiles
ls -lrt
lists the contents of the current working directory (meant to be /apps/common/bau/base/
here), and the only way to have /tmp/basefmxfiles
in that output is if there's some:
lrwxrwxrwx 1 user group 1 May 17 18:11 somelink -> foo/tmp/basefmxfilesbar
symlink in there, so it's unclear what you meant to do with that command.
else
echo "But the file is not modified in last 5 minutes"
fi
else
echo "$0: File '${file}' not found."
That's the else
part of your [ -f $file ]
, which checks whether $file
is a regular file, so the error (which should go to stderr) should rather be:
printf>&2 '%s\n' "$0: File '$file' not found as a regular file."
Here, you could do every thing with find
(again assuming GNU find
4.9 or above):
cd /apps/common/bau/base || exit
tr '\n' '\0' < /tmp/fmxfileslist |
find -L -files0-from - \
-prune \
-type f \
-printf '%p regular and last modified on %TFT%TT%Tz\n' \
'(' \
-mmin -5 -printf '%p regular and mtime > -5min\n' -o \
-printf '%p regular but older\n' \
')' -o -printf '%p not a regular files\n'
For files that find
can't access, it will print an error message on stderr.
Or you could use zsh
instead of sh
:
#! /bin/zsh -
cd /apps/common/bau/base || exit
files=( ${(f)"$(</tmp/fmxfileslist)"} )
regulars=( $^files(N-.) )
recent_regulars=( $^regulars(N-m-5) )
older_regulars=( ${regulars:|recent_regulars} )
non_regulars=( ${files:|regulars} )
accessible=( $^files(N-^@) )
inaccessible=( ${files:|accessible} )
And for instance print
the contents of those arrays r
aw on 1
C
olumn with print -rC1 -- $array
or iterate over them with for file ($array) something with $file
(there's no split+glob over unquoted parameter expansions in zsh, so it's fine to leave them unquoted there).
To get the last modification time of a file, before or after symlink resolution you can use its stat
builtin:
zmodload zsh/stat
stat -F %FT%T%z -H after -- $file &&
stat -LF %FT%T%z -H before -- $file &&
print -r "mtime before symlink resolution: $before[mtime]; after: $after[mtime]"
¹ On BSDs, you can use the find -f "$file" ...
syntax instead.
/tmp/fmxfile
, but your script reads filenames from/tmp/fmxfileslist
. Was that just an error in writing the question, and if not, what's in/tmp/fmxfileslist
? 2.) If your script actually reads/tmp/fmxfile
, the$file
will refer to those exact absolute paths listed in that file, not to anything under/apps/common/bau/base
. So your firstif
will look into a wrong place and your firstecho
will tell lies. 3.)date +%D
will just show the current date, not the creation date of any file. 4.)find
will never output "true" when used like that. – telcoM May 31 '23 at 07:24/apps/common/bau/base/fmx/eng/hint.fmx
only, or b) exactly/apps/common/bau/base/hint.fmx
only, or c)hint.fmx
in/apps/common/bau/base
or any sub-directory of it? – telcoM May 31 '23 at 07:42