我想如何显示没有特定文件的文件夹。但问题是,文件名相同但大小写不同。
案例分析: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
没有README
和toolb
没有readme
答案1
您不能用于find
查找不存在的文件。但是,您可以用来find
查找目录,然后测试这些目录中是否存在给定的文件名。
当使用find
查找目录时,请确保使用-type d
.然后测试每个找到的目录中的文件README
和readme
.
假设某些顶级目录具有以下目录层次结构projects
:
projects/
|-- toola
| |-- doc
| |-- readme
| `-- src
|-- toolb
| |-- doc
| `-- src
|-- toolc
| |-- README
| |-- doc
| `-- src
`-- toold
|-- doc
`-- src
用于查找直接位于其下不包含或文件的find
目录:projects
README
readme
$ 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