是否有任何理由使用“-f” bash 运算符仔细检查“find -type -f”结果?

是否有任何理由使用“-f” bash 运算符仔细检查“find -type -f”结果?

这个博客我找到了一个 bash 脚本(“片段”部分),其中包含以下结构来从中获取单个文件.bash_profile

if [ -d ~/.bash_profile.d ]; then
  for file in $( find ~/.bash_profile.d -type f )
  do
    if [ -f "$file" ]; then
      source "$file"
    fi
  done
fi

find -type f首先使用 bash 运算符过滤文件然后再次检查它们是否有意义-f,或者是某种拼凑而成的?

下面的脚本不也是一样吗?

if [ -d ~/.bash_profile.d ]; then
  for file in $( find ~/.bash_profile.d -type f )
  do
    source "$file"
  done
fi

如果不是,有什么区别?

答案1

这段代码有一些问题,但令人惊讶的是,双文件检查不是其中之一。

首先,正如 @EricRenouf 所示,$()周围的构造是错误的。find正确的方法是使用类似的东西

while read filename
do
    source $filename
done < <(find ....)

它在子 shell 中调用 find,并将文件名读入主filenameshell 中的变量(这是find | while read x它的想法,但不幸的是不可移植)

其次,-d目录test是多余的;find如果目录不存在,则不会找到任何文件,因此测试其存在没有意义。

然而,-type f的参数并没有测试与的参数find完全相同的东西。 POSIX 有以下内容-ftest关于test

-F 路径名

为真,如果路径名解析为常规文件的现有目录条目。如果路径名无法解析,或者路径名解析为非常规文件的现有目录条目,则返回 False。

并有这个关于find

-类型 C

如果文件的类型是,则主项应评估为 trueC, 在哪里C是 'b'、'c'、'd'、'l'、'p'、'f' 或 's',表示块特殊文件、字符特殊文件、目录、符号链接、FIFO、常规文件或套接字, 分别。

因此,如果您有一个“无法解析”的常规文件,那么您就有一个test -f将失败但find -type f会成功的文件。实现此目的的一种方法是在目录中放置一个您可以读取但无法访问的文件:

wouter@gangtai:~$ ls -ld foo
drw-r--r--. 2 wouter wouter 4096 apr  1 18:38 foo
wouter@gangtai:~$ find foo -type f | while read file; do if [ -f $file ]; then   echo $file tests -f; else   echo $file does not test -f; fi; done
foo/bar does not test -f
wouter@gangtai:~$ ls -l foo
ls: cannot access 'foo/bar': Permission denied
total 0
-????????? ? ? ? ?            ? bar

类型如果您对存储文件的目录具有 权限r,但没有 权限,则可以检测到文件(无论是目录、常规文件还是其他文件)的权限。x但是,为了能够“解决”它(即调用stat()该文件上的函数之一),您需要x该目录的权限位。

当然,在 shell 脚本中进行这样的测试是否对您.bashrc有用是另一回事。我想说不是。然而,这并不意味着这两个测试是相同的,而且这种差异的情况重要的...

答案2

for file in ~/.bash_profile.d/*

这不会找到任何以句点 (.) 开头的文件。为了捕获边缘情况,最好进行查找。

答案3

~/.bash_profile.d/*还将列出所有子目录,但不输入它们来获取其中的文件。
findwith-type f将排除子目录本身,并进入它们并从中获取文件。此外,find还将包括隐藏文件,但~/.bash_profile.d/*不会。

编辑:

检查[ -f "$file" ]是多余的。

答案4

您可能需要在此处仔细检查,因为您正在处理 的输出find,这意味着输出将受到分词的影响。如果find打印的名称中包含空格,那么您$file实际上不会通过-f测试,因为它只是文件名的一部分。

例如:

$ touch "~/.bash_profile.d/with space"
$ for f in $( find ~/.bash_profile.d -type f 2>/dev/null );do printf -- "--%s--\n" "$f"; done
--~/.bash_profile.d/with--
--space--

所以在这种情况下if [ -f "$f" ]不会返回 true,因为$f不指向文件

这是著名的另一个例子不要解析 ls问题

相关内容