如果目录中不存在文件名则查找命令

如果目录中不存在文件名则查找命令

我想如何显示没有特定文件的文件夹。但问题是,文件名相同但大小写不同。

案例分析:tools目录下,有的子目录包含readme/README文件,有的子目录没有。例如

/toola/readme
/toolb/README
/toolc/ (does not have readme file)

我希望 find 命令通过使用此命令仅显示 toolc 文件夹。

find . -maxdepth 2 ! -name '*readme*' -o ! -name '*README*' | awk -F "/" '{print $$2}' | uniq

但这不起作用。它显示所有文件,因为toola没有READMEtoolb没有readme

答案1

您不能用于find查找不存在的文件。但是,您可以用来find查找目录,然后测试这些目录中是否存在给定的文件名。

当使用find查找目录时,请确保使用-type d.然后测试每个找到的目录中的文件READMEreadme.

假设某些顶级目录具有以下目录层次结构projects

projects/
|-- toola
|   |-- doc
|   |-- readme
|   `-- src
|-- toolb
|   |-- doc
|   `-- src
|-- toolc
|   |-- README
|   |-- doc
|   `-- src
`-- toold
    |-- doc
    `-- src

用于查找直接位于其下不包含或文件的find目录:projectsREADMEreadme

$ find projects -mindepth 1 -maxdepth 1 -type d \
    ! -exec test -f {}/README ';' \
    ! -exec test -f {}/readme ';' -print
projects/toolb
projects/toold

在这里,我们找到直接在下面的任何目录projects,然后使用该test实用程序来确定找到的目录中哪个不包含这两个文件中的任何一个。

这完全相当于

find projects -mindepth 1 -maxdepth 1 -type d \
    -exec [ ! -f {}/README ] ';' \
    -exec [ ! -f {}/readme ] ';' -print

上述的另一种表述:

find projects -mindepth 1 -maxdepth 1 -type d -exec sh -c '
    for pathname do
        if [ ! -f "$pathname/README" ] &&
           [ ! -f "$pathname/readme" ]; then
            printf "%s\n" "$pathname"
        fi
    done' sh {} +

在这里,我们让一个小的内联 shell 脚本对这两个文件进行实际测试,并打印不包含其中任何一个的目录的路径名。该find实用程序的作用类似于目录路径名的“路径名生成器”,供内联脚本进行迭代。

事实上,如果目录结构是这样的,我们可能会选择find根本不使用:

for pathname in projects/*/; do
    if [ ! -f "$pathname/README" ] &&
       [ ! -f "$pathname/readme" ]; then
        printf '%s\n' "$pathname"
    fi
done

请注意模式中的尾部斜杠projects/*/。正是这一点使得模式仅匹配目录(或目录的符号链接)。

这样做与使用的区别find在于,使用上面的 shell 循环,我们将排除下面的隐藏目录project,并将包含目录的符号链接。

在所有情况下,我们都会迭代目录的路径名,并测试这两个文件名是否不存在。

唯一需要注意的是,该-f测试对于常规文件的符号链接也适用。

有关的:

答案2

鉴于我投票支持清晰优雅解决方案作者:Kusalananda,我补充说,这种任务看起来像是在集合上操作。单纯的工具find并不适合。事实上,它必须通过使用引入外部工具-exec

另一种方法是使用比较/差异工具。例如,假设您有权访问 GNUfind和支持进程替换的 shell(例如bash),并且路径中没有换行符:

comm -2 -3 <(find ./tool* -maxdepth 0 -type d | sort) \
<(find ./tool* -iname "readme" -printf "%H\n" | sort)

在哪里:

  • comm比较两个已排序逐行文件;这些选项-2 -3允许它从输出结果中删除仅在第二个文件或两个文件中的结果。
  • -printf "%H\n"让我们find只打印找到文件的起点,后跟一个新行(我们必须匹配-maxdepth 0定义其他列表的选项)。

用树测试:

$ find ./tool* -printf "%p %y\n" | sort
./toola d
./toola/doc d
./toola/readme f
./toola/src d
./toolb d
./toolb/doc d
./toolb/src d
./toolc d
./toolc/doc d
./toolc/README f
./toolc/src d
./toold d
./toold/doc d
./toold/doc/readme f
./toold/src d

上面的命令给出:

./toolb

答案3

zsh

set -o extendedglob # for (#i) for case insensitive matching

all_projects=(projects/*(-/))
typeset -aU projects_with_readme # -U for unique
projects_with_readme=(projects/*/(#i)readme(:h))
projects_without_readme=(${all_projects:|projects_with_readme})

echo Projects with READMEs:
printf ' - %s\n' $projects_with_readme
echo Projects without READMEs:
printf ' - %s\n' $projects_without_readme

您可以更改 to(#i)readme(#i)*readme*考虑名为README.txt或 的文件000README,或者(:h)更改(-.:h)to 仅考虑自述文件文件是常规的符号链接解析后(排除目录、损坏的链接和其他特殊类型的文件)。

答案4

我会使用以下内容:

find -type d -maxdepth 2 -not -name '*readme*' | awk -F "/" '{print $$2}' | uniq

相关内容