我正在努力在 if 条件下编写一个 find 命令,让我先分享一下我的要求。我在名为 /tmp/fmxfile 的文件中有一个文件列表
cat /tmp/fmxfile
/fmx/eng/hint.fmx
/pll/case.pll
/plx/eng/case.plx
我正在文件上方编写一个 for 循环,(如果条件通过,则查找不同路径中的每个文件)首先在第一个 IF 条件中,我想检查文件是否在该路径中 在第二个 IF 条件中,我想查找是否该文件在最后 5 分钟内被修改,如果是 true 则将该文件复制到 /tmp 路径。
cd /apps/common/bau/base/
for file in `cat /tmp/fmxfileslist`
do
if [ -f $file ]
then
echo "File '${file}' found in $(pwd) path and created on $(date +%D)."
if [ $(find $file -mmin -5 -type f) ="true" ];
then
cp -a $file /tmp/basefmxfiles
ls -lrt | grep /tmp/basefmxfiles
else
echo "But the file is not modified in last 5 minutes"
fi
else
echo "$0: File '${file}' not found."
fi
done
答案1
对您的代码的一些评论(假设它是sh
语法中的):
cd /apps/common/bau/base/
您没有检查 的退出状态cd
,因此如果失败,您将继续在当前工作目录中运行脚本的其余部分,无论它是什么。
for file in `cat /tmp/fmxfileslist`
它在已弃用的命令替换形式之上使用 split+glob `...`
,而您似乎想要迭代文件的行,其语法为:
while IFS= read -r file <&3; do
...
done 3< /tmp/fmxfileslist
(或者应该改为/tmp/fmxfile
)?
/tmp
另请注意,从安全角度来看,在全局可写目录中使用具有固定名称的文件(例如)是不好的做法。
另外,示例列表中的路径都不是相对的,所以当前工作目录是什么有关系吗?或者列表应该是:
fmx/eng/hint.fmx
pll/case.pll
plx/eng/case.plx
反而?或者应该将前导/
删除或.
插入到它之前?
do if [ -f $file ]
这是在 的扩展上再次使用 split+glob $file
,这是没有意义的。您可能的意思是[ -f "$file" ]
如果目的是检查该文件是否存在、您是否可以访问并且可以确定为常规的(不是目录、fifo、设备、套接字...)符号链接解析后。
then echo "File '${file}' found in $(pwd) path and created on $(date +%D)."
$(pwd)
这次可以使用现代形式的命令替换$PWD
在 POSIX shell 中编写。date +%D
打印当前日期。要打印 的最后修改时间$file
,假设是 GNU date
,您可以使用该-r
选项。%D
给出的日期mm/dd/yy
格式非常模糊,并且不提供任何时间或时区信息。$(date -r "$file" +%FT%T%z || echo UNKNOWN)
。
另请注意,echo
不能用于任意数据。代替使用printf '%s\n' "..."
。
if [ $(find $file -mmin -5 -type f) ="true" ];
$file
再次,对 和的输出使用 split+glob find
。您还缺少一个空格,因此=
该[
命令不会看到=
比较运算符参数,而是看到一个伪造的=true
参数。
另外,正如find
将打印它找到的文件路径一样,它只会打印true
if $file
is true
(true
后跟任意数量的换行符也可以工作,因为尾随换行符会被命令替换删除,但是当您在读取fmxfileslist
文件的一行时有时,这种情况不会发生;IOW 您的fmxfileslist
文件不能包含任意文件名)。
另请注意,以(also on , ...)find
开头的文件名会导致阻塞。-
!
(
对于-type f
常规文件的符号链接返回 false,而[ -f "$file" ]
上面的则返回 true。您需要特定的 GNU-xtype f
来获得两者之间的一致性,或者还用于 -L
检查符号链接目标的修改时间(同样date -r
如此),因此,假设 GNU find
4.9 或更高版本:
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
find
这里在的 stdin上传递以 NUL 分隔的文件路径(它从那里获取-files0-from -
,需要 4.9 或更高版本的部分),而不是作为参数来避免上面提到的令人窒息的问题。
then cp -a $file /tmp/basefmxfiles
同样,毫无意义的 split+glob,而且您还缺少--
选项分隔符。如果/tmp/basefmxfiles
事先不存在作为目录,则会将其创建为副本$file
,因此最好将 a 附加/
到目标目录的末尾以避免这种情况(或者在这里,因为您已经在使用 GNUisms,所以使用GNUcp
的-t
选项):
cp -a -- "$file" /tmp/basefmxfiles/
cp -at /tmp/basefmxfiles -- "$file"
ls -lrt | grep /tmp/basefmxfiles
ls -lrt
列出当前工作目录的内容(应该/apps/common/bau/base/
在这里),并且在该输出中包含的唯一方法/tmp/basefmxfiles
是如果有:
lrwxrwxrwx 1 user group 1 May 17 18:11 somelink -> foo/tmp/basefmxfilesbar
符号链接在那里,所以不清楚你想用这个命令做什么。
else echo "But the file is not modified in last 5 minutes" fi else echo "$0: File '${file}' not found."
这是else
你的部分[ -f $file ]
,它检查是否$file
是常规的文件,因此错误(应该转到 stderr)应该是:
printf>&2 '%s\n' "$0: File '$file' not found as a regular file."
在这里,您可以使用以下命令完成所有操作find
(再次假设 GNU find
4.9 或更高版本):
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'
对于无法访问的文件find
,它会在 stderr 上打印错误消息。
或者你可以使用zsh
而不是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} )
例如,print
这些数组的内容r
aw 在1
C
olumn 上 withprint -rC1 -- $array
或对它们进行迭代for file ($array) something with $file
(zsh 中没有对未加引号的参数扩展进行 split+glob,因此可以将它们保留在那里不加引号)。
要获取文件的最后修改时间,在符号链接解析之前或之后,您可以使用其stat
内置函数:
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]"
¹ 在 BSD 上,您可以改用该find -f "$file" ...
语法。