Linux shell 脚本中带有 find 命令的 if 条件

Linux shell 脚本中带有 find 命令的 if 条件

我正在努力在 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将打印它找到的文件路径一样,它只会打印trueif $fileis true(true后跟任意数量的换行符也可以工作,因为尾随换行符会被命令替换删除,但是当您在读取fmxfileslist文件的一行时有时,这种情况不会发生;IOW 您的fmxfileslist文件不能包含任意文件名)。

另请注意,以(also on , ...)find开头的文件名会导致阻塞。-!(

对于-type f常规文件的符号链接返回 false,而[ -f "$file" ]上面的则返回 true。您需要特定的 GNU-xtype f来获得两者之间的一致性,或者还用于 -L检查符号链接目标的修改时间(同样date -r如此),因此,假设 GNU find4.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 find4.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这些数组的内容raw 在1 Column 上 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" ...语法。

相关内容