
[英]How to exclude multiple subdirectories (same directory name) when using find command to delete files older than 30 days in a batch file?
[英]How do I exclude a directory when using `find`?
使用find
搜索*.js
文件时如何排除特定目录?
find . -name '*.js'
如果-prune
对您不起作用,这将:
find -name "*.js" -not -path "./directory/*"
警告:需要遍历所有不需要的目录。
使用-prune
主选项。 例如,如果您想排除./misc
:
find . -path ./misc -prune -o -name '*.txt' -print
排除多个目录,或在括号之间。
find . -type d \( -path ./dir1 -o -path ./dir2 -o -path ./dir3 \) -prune -o -name '*.txt' -print
而且,要在任何级别排除具有特定名称的目录,请使用-name
primary 而不是-path
。
find . -type d -name node_modules -prune -o -name '*.json' -print
我发现以下内容比其他建议的解决方案更容易推理:
find build -not \( -path build/external -prune \) -name \*.js
# you can also exclude multiple paths
find build -not \( -path build/external -prune \) -not \( -path build/blog -prune \) -name \*.js
重要提示:您在-path
之后键入的路径必须与find
不排除打印的内容完全匹配。 如果这句话让您感到困惑,您只需确保在整个命令中使用完整路径,如下所示: find /full/path/ -not \( -path /full/path/exclude/this -prune \) ...
。 如果您想更好地理解,请参阅注释 [1]。
\(
和\)
内部是一个表达式,它将与build/external
完全匹配(请参阅上面的重要说明),并且在成功时将避免遍历下面的任何内容。 然后将其分组为带有转义括号的单个表达式,并以-not
为前缀,这将使find
跳过与该表达式匹配的任何内容。
有人可能会问,添加-not
是否不会使所有其他被-prune
隐藏的文件重新出现,答案是否定的。 -prune
的工作方式是,一旦到达,该目录下的文件将被永久忽略。
这来自一个实际的用例,我需要在 Wintersmith 生成的一些文件上调用 yui-compressor,但忽略了其他需要按原样发送的文件。
注意[1] :如果您想排除/tmp/foo/bar
并且像这样运行 find “ find /tmp \(...
”,那么您必须指定-path /tmp/foo/bar
。另一方面,如果你像这样运行 find cd /tmp; find . \(...
那么你必须指定-path ./foo/bar
。
对于跳过目录的首选语法应该是什么,这里显然有些混淆。
GNU 意见
To ignore a directory and the files under it, use -prune
推理
-prune
阻止find
下降到目录中。 仅指定-not -path
仍会下降到跳过的目录,但-not -path
将在find
测试每个文件时为假。
-prune
的问题
-prune
做它打算做的事情,但在使用它时仍然需要注意一些事情。
find
打印修剪后的目录。
-prune
仅适用于-print
而没有其他操作。
-prune
适用于除-delete
之外的任何操作。 为什么它不适用于删除? 为了使-delete
起作用,find 需要按 DFS 顺序遍历目录,因为-delete
将首先删除叶子,然后是叶子的父节点,等等......但是为了使-prune
指定有意义, find
需要点击目录并停止对其进行降序,这显然对-depth
或-delete
没有意义。表现
我对该问题的三个最受好评的答案进行了简单测试(将-print
替换为-exec bash -c 'echo $0' {} \;
以显示另一个动作示例)。 结果如下
----------------------------------------------
# of files/dirs in level one directories
.performance_test/prune_me 702702
.performance_test/other 2
----------------------------------------------
> find ".performance_test" -path ".performance_test/prune_me" -prune -o -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
[# of files] 3 [Runtime(ns)] 23513814
> find ".performance_test" -not \( -path ".performance_test/prune_me" -prune \) -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
[# of files] 3 [Runtime(ns)] 10670141
> find ".performance_test" -not -path ".performance_test/prune_me*" -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
[# of files] 3 [Runtime(ns)] 864843145
结论
f10bit 的语法和Daniel C. Sobral 的语法平均需要 10-25 毫秒才能运行。 GetFree 的语法(不使用-prune
)耗时 865 毫秒。 所以,是的,这是一个相当极端的例子,但是如果你关心运行时间并且正在做任何远程密集的事情,你应该使用-prune
。
注意Daniel C. Sobral 的语法在两种-prune
语法中表现更好; 但是,我强烈怀疑这是某些缓存的结果,因为切换两者运行的顺序会导致相反的结果,而非修剪版本总是最慢。
测试脚本
#!/bin/bash
dir='.performance_test'
setup() {
mkdir "$dir" || exit 1
mkdir -p "$dir/prune_me/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/w/x/y/z" \
"$dir/other"
find "$dir/prune_me" -depth -type d -exec mkdir '{}'/{A..Z} \;
find "$dir/prune_me" -type d -exec touch '{}'/{1..1000} \;
touch "$dir/other/foo"
}
cleanup() {
rm -rf "$dir"
}
stats() {
for file in "$dir"/*; do
if [[ -d "$file" ]]; then
count=$(find "$file" | wc -l)
printf "%-30s %-10s\n" "$file" "$count"
fi
done
}
name1() {
find "$dir" -path "$dir/prune_me" -prune -o -exec bash -c 'echo "$0"' {} \;
}
name2() {
find "$dir" -not \( -path "$dir/prune_me" -prune \) -exec bash -c 'echo "$0"' {} \;
}
name3() {
find "$dir" -not -path "$dir/prune_me*" -exec bash -c 'echo "$0"' {} \;
}
printf "Setting up test files...\n\n"
setup
echo "----------------------------------------------"
echo "# of files/dirs in level one directories"
stats | sort -k 2 -n -r
echo "----------------------------------------------"
printf "\nRunning performance test...\n\n"
echo \> find \""$dir"\" -path \""$dir/prune_me"\" -prune -o -exec bash -c \'echo \"\$0\"\' {} \\\;
name1
s=$(date +%s%N)
name1_num=$(name1 | wc -l)
e=$(date +%s%N)
name1_perf=$((e-s))
printf " [# of files] $name1_num [Runtime(ns)] $name1_perf\n\n"
echo \> find \""$dir"\" -not \\\( -path \""$dir/prune_me"\" -prune \\\) -exec bash -c \'echo \"\$0\"\' {} \\\;
name2
s=$(date +%s%N)
name2_num=$(name2 | wc -l)
e=$(date +%s%N)
name2_perf=$((e-s))
printf " [# of files] $name2_num [Runtime(ns)] $name2_perf\n\n"
echo \> find \""$dir"\" -not -path \""$dir/prune_me*"\" -exec bash -c \'echo \"\$0\"\' {} \\\;
name3
s=$(date +%s%N)
name3_num=$(name3 | wc -l)
e=$(date +%s%N)
name3_perf=$((e-s))
printf " [# of files] $name3_num [Runtime(ns)] $name3_perf\n\n"
echo "Cleaning up test files..."
cleanup
这适用于 macOS 和 Ubuntu:
find / -name MyFile ! -path '*/Directory/*'
搜索“我的文件”,不包括“目录”。 注意星星*
。
一种选择是使用 grep 排除包含目录名称的所有结果。 例如:
find . -name '*.js' | grep -v excludeddir
我更喜欢-not
表示法......它更具可读性:
find . -name '*.js' -and -not -path directory
在 Linux Ubuntu 18.04 和 20.04 中测试。
请注意,要排除的文件夹名称之前的./
(或*/
,见下文)和后面的/*
(或*
,但请参阅下面的警告)是必需的,以便排除dir_to_exclude
以及其中的任何内容!
此外,对于 speed和不遍历排除目录,请注意真正重要的转义分组括号和-prune
选项。 例如: find -not \( -path "*/dir_to_exclude/*" -prune \)
。
要在手册页中查看这些转义分组括号的示例,请运行man find
,然后按/进行搜索。 搜索模式\(
,例如,使用正则表达式模式\\\(
。按Enter开始搜索手册页。搜索时按N表示“下一个匹配项”。
这些工作:
# [my favorite #1] exclude contents of `dir_to_exclude` at the search root
find -not -path "./dir_to_exclude/*"
# exclude all files & folders beginning with the name `dir_to_exclude` at the
# search root
find -not -path "./dir_to_exclude*"
# [my favorite #2] exclude contents of `dir_to_exclude` at any level within your
# search path
find -not -path "*/dir_to_exclude/*"
# exclude all files & folders beginning with the name `dir_to_exclude` at any
# level within your search path
find -not -path "*/dir_to_exclude*"
# To exclude multiple matching patterns, use `-not -path "*/matching pattern/*"`
# multiple times, like this
find -not -path "*/dir_to_exclude1/*" -not -path "*/dir_to_exclude2/*"
[使用这些] 这些也有效,并且更好,因为它们导致 find 不会不必要地遍历排除的路径!:
(这会在速度上产生巨大差异(快 2 倍~100 倍)!请参见此处和此处。您还可以使用转义的搜索字符串\\\(
和\\\)
在本地搜索man find
pages 以查找字符串\(
和\)
\\\)
,分别)。
find -not \( -path "./dir_to_exclude" -prune \) # works here but not above
find -not \( -path "./dir_to_exclude*" -prune \)
find -not \( -path "./dir_to_exclude/*" -prune \)
find -not \( -path "*/dir_to_exclude" -prune \) # works here but not above
find -not \( -path "*/dir_to_exclude*" -prune \)
find -not \( -path "*/dir_to_exclude/*" -prune \)
# To exclude multiple matching patterns at once, use the `-not \( ... \)`
# pattern multiple times, like this
find -not \( -path "*/dir_to_exclude1/*" -prune \) \
-not \( -path "*/dir_to_exclude2/*" -prune \)
...但这些不起作用:
# These do NOT work!
find -not -path "dir_to_exclude"
find -not -path "dir_to_exclude/*"
find -not -path "./dir_to_exclude"
find -not -path "./dir_to_exclude/"
关键是,通常,要使其工作,您必须以./
或*/
开始每个匹配模式,并以/*
或*
结束每个匹配模式,具体取决于您要实现的目标。 我说“一般”,因为在上面的-not \( ... \)
样式部分中有两个值得注意的例外。 您可以通过它们右侧的注释来识别这两个例外: # works here but not above
。
dir_to_exclude
中的所有文件和文件夹。 请注意,这排除了dir_to_exclude
中的所有子文件和子文件夹,但不排除dir_to_exclude
目录本身。 find -not \( -path "./dir_to_exclude/*" -prune \)
dir_to_exclude
目录本身(以及名称以这些字符开头的任何文件或文件夹)。 警告:这也排除dir_to_exclude1
、 dir_to_exclude2
、 dir_to_exclude_anyTextHere
等。它排除了仅以文本dir_to_exclude
并且位于您正在搜索的根目录中的任何文件或文件夹。 find -not \( -path "./dir_to_exclude*" -prune \)
*
也添加到路径的前面,而不是使用.
表示搜索根目录。 find -not \( -path "*/dir_to_exclude/*" -prune \)
dir_to_exclude
开头的任何文件或文件夹。 (另见上面的警告)。 find -not \( -path "*/dir_to_exclude*" -prune \)
在./
中, .
开头的意思是“从当前目录开始”(或在*/
中, *
是一个通配符,用于选择到目前为止的任何字符),在/*
结尾, *
是一个通配符,用于选择任何/
字符后的路径字符串中的字符。 这意味着以下内容:
"./dir_to_exclude/*"
匹配根搜索目录 ( ./
) 中dir_to_exclude
中的所有子文件和子文件夹,但不匹配目录本身。"./dir_to_exclude*"
匹配根搜索目录 ( ./
) 中的所有文件和文件夹,包括dir_to_exclude
以及其中的所有内容,但需要注意的是,它将匹配以字符dir_to_exclude
开头的任何文件或文件夹名称."*/dir_to_exclude/*"
匹配搜索路径 ( */
)中任何级别的任何目录中的dir_to_exclude
中的所有子文件和子文件夹,但不匹配目录本身。"*/dir_to_exclude*"
匹配搜索路径中任何级别 ( */
) 中名称以dir_to_exclude
开头的所有文件和文件夹。从那里,我喜欢通过管道连接到grep
以在感兴趣的路径中搜索某些匹配模式。 例如:搜索dir_to_exclude
目录中的任何路径,并且其中包含desired_file_name.txt
:
# Case-sensitive; notice I use `\.` instead of `.` when grepping, in order to
# search for the literal period (`.`) instead of the regular expression
# wildcard char, which is also a period (`.`).
find -not \( -path "./dir_to_exclude/*" -prune \) \
| grep "desired_file_name\.txt"
# Case-INsensitive (use `-i` with your `grep` search)
find -not \( -path "./dir_to_exclude/*" -prune \) \
| grep -i "desired_file_name\.txt"
# To make `dir_to_exclude` also case INsensitive, use the `find` `-ipath` option
# instead of `-path`:
find -not -ipath \( -path "./dir_to_exclude/*" -prune \) \
| grep -i "desired_file_name\.txt"
要排除多个匹配模式,只需多次使用-not \( -path "*/matching pattern/*" -prune \)
。 前任:
# Exclude all ".git" and "..git" dirs at any level in your search path
find -not \( -path "*/.git/*" -prune \) -not \( -path "*/..git/*" -prune \)
我在这里使用上面的示例作为我的sublf
别名的一部分(更新:该别名正在被扩展并移动到这里文件夹中的sublf.sh
脚本中)。 这个别名允许我使用fzf
模糊查找器在 Sublime Text 中快速搜索和打开多个文件。 有关最新版本,请参阅上面的链接。
alias sublf='FILES_SELECTED="$(find -not \( -path "*/.git/*" -prune \) \
-not \( -path "*/..git/*" -prune \) \
| fzf -m)" \
&& echo "Opening these files in Sublime Text:" \
&& echo "$FILES_SELECTED" \
&& subl $(echo "$FILES_SELECTED")'
关键字:在 find 命令中排除 dir; 不要用 find 搜索路径; 不区分大小写的 find 和 grep 命令
使用 -prune 选项。 所以,像:
find . -type d -name proc -prune -o -name '*.js'
'-type d -name proc -prune' 仅查找名为 proc 的目录以排除。
“-o”是一个“或”运算符。
-prune
绝对有效,并且是最好的答案,因为它可以防止下降到您要排除的目录。 -not -path
仍然搜索排除的目录,它只是不打印结果,如果排除的目录是安装的网络卷或者您没有权限,这可能是一个问题。
棘手的部分是find
对参数的顺序非常特别,所以如果你没有把它们弄得恰到好处,你的命令可能不起作用。 参数的顺序通常是这样的:
find {path} {options} {action}
{path}
:将所有与路径相关的参数放在首位,例如. -path './dir1' -prune -o
. -path './dir1' -prune -o
{options}
:将-name, -iname, etc
作为该组中的最后一个选项时,我取得了最大的成功。 例如-type f -iname '*.js'
{action}
:您需要在使用-prune
时添加-print
这是一个工作示例:
# setup test
mkdir dir1 dir2 dir3
touch dir1/file.txt; touch dir1/file.js
touch dir2/file.txt; touch dir2/file.js
touch dir3/file.txt; touch dir3/file.js
# search for *.js, exclude dir1
find . -path './dir1' -prune -o -type f -iname '*.js' -print
# search for *.js, exclude dir1 and dir2
find . \( -path './dir1' -o -path './dir2' \) -prune -o -type f -iname '*.js' -print
这是我用来排除某些路径的格式:
$ find ./ -type f -name "pattern" ! -path "excluded path" ! -path "excluded path"
我用它来查找不在“。*”路径中的所有文件:
$ find ./ -type f -name "*" ! -path "./.*" ! -path "./*/.*"
有很多好的答案,只是我花了一些时间来理解命令的每个元素的用途及其背后的逻辑。
find . -path ./misc -prune -o -name '*.txt' -print
find 将开始在当前目录中查找文件和目录,因此find .
.
-o
选项代表逻辑 OR 并将命令的两个部分分开:
[ -path ./misc -prune ] OR [ -name '*.txt' -print ]
任何不是./misc 目录的目录或文件都不会通过第一个测试-path ./misc
。 但它们将针对第二个表达式进行测试。 如果他们的名字对应于*.txt
模式,他们就会被打印出来,因为-print
选项。
当 find 到达 ./misc 目录时,该目录只满足第一个表达式。 因此-prune
选项将应用于它。 它告诉 find 命令不要探索该目录。 因此 ./misc 中的任何文件或目录都不会被 find 探索,不会针对表达式的第二部分进行测试,也不会被打印。
-path -prune 方法也适用于路径中的通配符。 这是一个查找语句,它将查找服务于多个 git 存储库的 git 服务器的目录,而忽略了 git 内部目录:
find . -type d \
-not \( -path */objects -prune \) \
-not \( -path */branches -prune \) \
-not \( -path */refs -prune \) \
-not \( -path */logs -prune \) \
-not \( -path */.git -prune \) \
-not \( -path */info -prune \) \
-not \( -path */hooks -prune \)
如果有人正在研究如何一次忽略多条路径。 您可以使用 bash 数组(在 GNU bash 版本 4.4.20(1)-release 上完美运行)
#!/usr/bin/env bash
# This script helps ignore unnecessary dir paths while using the find command
EXCLUDE_DIRS=(
"! -path /*.git/*"
"! -path /*go/*"
"! -path /*.bundle/*"
"! -path /*.cache/*"
"! -path /*.local/*"
"! -path /*.themes/*"
"! -path /*.config/*"
"! -path /*.codeintel/*"
"! -path /*python2.7/*"
"! -path /*python3.6/*"
"! -path /*__pycache__/*"
)
find $HOME -type f ${EXCLUDE_DIRS[@]}
# if you like fzf
find $HOME -type f ${EXCLUDE_DIRS[@]} | fzf --height 40% --reverse
同样出于某种原因,您将无法忽略 /bin/ 目录路径。
要排除多个目录:
find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" \)
要添加目录,请添加-o -path "./dirname/*"
:
find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" -o -path "./dir3/*"\)
但也许你应该使用正则表达式,如果有很多目录要排除。
避免打印修剪目录的一个好技巧是在 -print 的右侧-or
-prune
之后使用-print
(也适用于-exec
)。 例如, ...
find . -path "*/.*" -prune -or -iname "*.j2"
将打印当前目录下所有扩展名为“.j2”的文件的路径,跳过所有隐藏目录。整洁。但它也会打印打印正在跳过的每个目录的完整路径,如上所述。但是,以下不,...
find . -path "*/.*" -prune -or -iname "*.j2" -print
因为从逻辑上讲,在-iname
运算符之后和 -print 之前有一个隐藏的-and
。 由于操作的布尔顺序和关联性,这会将其绑定到-or
子句的右侧部分。 但是文档说如果没有指定它(或其任何表亲...... -print0
等),则存在隐藏的-print
。 那么为什么-or
的左边部分不打印呢? 显然(而且我在第一次阅读手册页时并没有理解这一点),如果没有-print
-or -exec
ANYWHERE,那就是真的,在这种情况下,-print 在逻辑上会散布在周围,以便打印所有内容。 如果甚至在任何子句中都表达了 ONE print
样式的操作,那么所有那些隐藏的逻辑操作都会消失,您只会得到您指定的内容。 现在坦率地说,我可能更喜欢它,但是只有描述性运算符的find
显然不会做任何事情,所以我想它是有道理的。 如上所述,这也适用于-exec
,因此以下为具有所需扩展名的每个文件提供了完整的ls -la
列表,但没有列出每个隐藏目录的第一级,...
find . -path "*/.*" -prune -or -iname "*.j2" -exec ls -la -- {} +
对我(和这个线程上的其他人)来说, find
语法很快就会变得非常巴洛克,所以我总是加上括号以确保我知道什么绑定到什么,所以我通常为类型能力创建一个宏并形成所有这样的语句...
find . \( \( ... description of stuff to avoid ... \) -prune \) -or \
\( ... description of stuff I want to find ... [ -exec or -print] \)
以这种方式将世界分为两部分,很难出错。 我希望这会有所帮助,尽管似乎任何人都不太可能阅读到第 30 多个答案并投票赞成,但人们可以希望。 :-)
对于一个可行的解决方案(在 Ubuntu 12.04(Precise Pangolin)上测试)...
find ! -path "dir1" -iname "*.mp3"
将在当前文件夹和子文件夹中搜索 MP3 文件,但 dir1 子文件夹除外。
利用:
find ! -path "dir1" ! -path "dir2" -iname "*.mp3"
...排除 dir1 AND dir2
find . \( -path '.**/.git' -o -path '.**/.hg' \) -prune -o -name '*.js' -print
上面的示例查找当前目录下的所有*.js
文件,不包括文件夹.git
和.hg
,无论这些.git
和.hg
文件夹有多深。
注意:这也有效:
find . \( -path '.*/.git' -o -path '.*/.hg' \) -prune -o -name '*.js' -print
但我更喜欢**
表示法,以便与其他一些在这里无关紧要的工具保持一致。
find -name '*.js' -not -path './node_modules/*' -not -path './vendor/*'
似乎与
find -name '*.js' -not \( -path './node_modules/*' -o -path './vendor/*' \)
并且更容易记住 IMO。
您还可以使用正则表达式来包含/排除某些文件 /dirs 您的搜索使用如下内容:
find . -regextype posix-egrep -regex ".*\.(js|vue|s?css|php|html|json)$" -and -not -regex ".*/(node_modules|vendor)/.*"
这只会为您提供所有 js、vue、css 等文件,但不包括node_modules
和vendor
文件夹中的所有文件。
以前的答案在 Ubuntu 上都不好。 尝试这个:
find . ! -path "*/test/*" -type f -name "*.js" ! -name "*-min-*" ! -name "*console*"
我在这里找到了这个
您可以使用 prune 选项来实现此目的。 例如:
find ./ -path ./beta/* -prune -o -iname example.com -print
或者反向 grep “grep -v” 选项:
find -iname example.com | grep -v beta
您可以在Linux 查找命令排除目录搜索中找到详细说明和示例。
find . -name '*.js' -\! -name 'glob-for-excluded-dir' -prune
TLDR:了解您的根目录并从那里定制您的搜索,使用-path <excluded_path> -prune -o
选项。 不要在排除路径的末尾包含尾随/
。
例子:
find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
为了有效地使用find
我相信必须很好地了解您的文件系统目录结构。 在我的家用计算机上,我有多 TB 硬盘驱动器,其中大约一半的内容使用rsnapshot
(即rsync
)备份。 虽然备份到物理上独立(重复)的驱动器,但它安装在我的系统根 ( /
) 目录下: /mnt/Backups/rsnapshot_backups/
:
/mnt/Backups/
└── rsnapshot_backups/
├── hourly.0/
├── hourly.1/
├── ...
├── daily.0/
├── daily.1/
├── ...
├── weekly.0/
├── weekly.1/
├── ...
├── monthly.0/
├── monthly.1/
└── ...
/mnt/Backups/rsnapshot_backups/
目录目前占用约 2.9 TB,有约 60M 文件和文件夹; 简单地遍历这些内容需要时间:
## As sudo (#), to avoid numerous "Permission denied" warnings:
time find /mnt/Backups/rsnapshot_backups | wc -l
60314138 ## 60.3M files, folders
34:07.30 ## 34 min
time du /mnt/Backups/rsnapshot_backups -d 0
3112240160 /mnt/Backups/rsnapshot_backups ## 3.1 TB
33:51.88 ## 34 min
time rsnapshot du ## << more accurate re: rsnapshot footprint
2.9T /mnt/Backups/rsnapshot_backups/hourly.0/
4.1G /mnt/Backups/rsnapshot_backups/hourly.1/
...
4.7G /mnt/Backups/rsnapshot_backups/weekly.3/
2.9T total ## 2.9 TB, per sudo rsnapshot du (more accurate)
2:34:54 ## 2 hr 35 min
因此,每当我需要在我的/
(根)分区上搜索文件时,我都需要处理(如果可能的话,避免)遍历我的备份分区。
例子
在这个线程( 如何在 find . command 中排除目录)中提出的各种方法中,我发现使用接受的答案进行搜索要快得多——但有一些警告。
解决方案 1
假设我想找到系统文件libname-server-2.a
,但我不想搜索我的rsnapshot
备份。 要快速查找系统文件,请使用排除路径/mnt
(即,使用/mnt
,而不是/mnt/
,或/mnt/Backups
,或...):
## As sudo (#), to avoid numerous "Permission denied" warnings:
time find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
/usr/lib/libname-server-2.a
real 0m8.644s ## 8.6 sec <<< NOTE!
user 0m1.669s
sys 0m2.466s
## As regular user (victoria); I also use an alternate timing mechanism, as
## here I am using 2>/dev/null to suppress "Permission denied" warnings:
$ START="$(date +"%s")" && find 2>/dev/null / -path /mnt -prune -o \
-name "*libname-server-2.a*" -print; END="$(date +"%s")"; \
TIME="$((END - START))"; printf 'find command took %s sec\n' "$TIME"
/usr/lib/libname-server-2.a
find command took 3 sec ## ~3 sec <<< NOTE!
...在几秒钟内找到该文件,而这需要更长的时间(似乎递归通过所有“排除”目录):
## As sudo (#), to avoid numerous "Permission denied" warnings:
time find / -path /mnt/ -prune -o -name "*libname-server-2.a*" -print
find: warning: -path /mnt/ will not match anything because it ends with /.
/usr/lib/libname-server-2.a
real 33m10.658s ## 33 min 11 sec (~231-663x slower!)
user 1m43.142s
sys 2m22.666s
## As regular user (victoria); I also use an alternate timing mechanism, as
## here I am using 2>/dev/null to suppress "Permission denied" warnings:
$ START="$(date +"%s")" && find 2>/dev/null / -path /mnt/ -prune -o \
-name "*libname-server-2.a*" -print; END="$(date +"%s")"; \
TIME="$((END - START))"; printf 'find command took %s sec\n' "$TIME"
/usr/lib/libname-server-2.a
find command took 1775 sec ## 29.6 min
解决方案 2
该线程中提供的另一个解决方案( SO#4210042 )也表现不佳:
## As sudo (#), to avoid numerous "Permission denied" warnings:
time find / -name "*libname-server-2.a*" -not -path "/mnt"
/usr/lib/libname-server-2.a
real 33m37.911s ## 33 min 38 sec (~235x slower)
user 1m45.134s
sys 2m31.846s
time find / -name "*libname-server-2.a*" -not -path "/mnt/*"
/usr/lib/libname-server-2.a
real 33m11.208s ## 33 min 11 sec
user 1m22.185s
sys 2m29.962s
总结 | 结论
使用“解决方案 1 ”中说明的方法
find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
IE
... -path <excluded_path> -prune -o ...
请注意,每当您将尾随/
添加到排除路径时, find
命令都会递归地进入(所有这些) /mnt/*
目录——在我的情况下,由于/mnt/Backups/rsnapshot_backups/*
子目录,还包括约 2.9 TB 的文件可供搜索! 通过不附加尾随/
搜索应该几乎立即完成(在几秒钟内)。
“解决方案 2” ( ... -not -path <exclude path> ...
) 同样似乎递归地搜索排除的目录——不返回排除的匹配项,但不必要地消耗搜索时间。
在这些rsnapshot
备份中搜索:
要在我的每小时/每天/每周/每月rsnapshot
备份之一中查找文件):
$ START="$(date +"%s")" && find 2>/dev/null /mnt/Backups/rsnapshot_backups/daily.0 -name '*04t8ugijrlkj.jpg'; END="$(date +"%s")"; TIME="$((END - START))"; printf 'find command took %s sec\n' "$TIME"
/mnt/Backups/rsnapshot_backups/daily.0/snapshot_root/mnt/Vancouver/temp/04t8ugijrlkj.jpg
find command took 312 sec ## 5.2 minutes: despite apparent rsnapshot size
## (~4 GB), it is in fact searching through ~2.9 TB)
排除嵌套目录:
在这里,我想在 /mnt/Vancouver/projects/ 搜索时排除嵌套目录,例如 /mnt /mnt/Vancouver/projects/
/mnt/Vancouver/projects/ie/claws/data/*
:
$ time find . -iname '*test_file*'
./ie/claws/data/test_file
./ie/claws/test_file
0:01.97
$ time find . -path '*/data' -prune -o -iname '*test_file*' -print
./ie/claws/test_file
0:00.07
另外:在命令末尾添加-print
会抑制排除目录的打印输出:
$ find / -path /mnt -prune -o -name "*libname-server-2.a*"
/mnt
/usr/lib/libname-server-2.a
$ find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
/usr/lib/libname-server-2.a
以下命令有效:
find . -path ./.git -prune -o -print
如果 find 有问题,使用-D tree
选项查看表达式分析信息。
find -D tree . -path ./.git -prune -o -print
或者-D all
,查看所有执行信息。
find -D all . -path ./.git -prune -o -print
这适合我在 Mac 上:
find . -name *.php -or -path "./vendor" -prune -or -path "./app/cache" -prune
它将排除以php
为后缀的搜索名称的vendor
和app/cache
目录。
我使用find
为xgettext
提供文件列表,并希望省略特定目录及其内容。 我尝试了许多-path
与-prune
组合的排列,但无法完全排除我想要消失的目录。
虽然我能够忽略我想要忽略的目录的内容,但find
然后将目录本身作为结果之一返回,这导致xgettext
崩溃(不接受目录;仅文件)。
我的解决方案是简单地使用grep -v
跳过结果中我不想要的目录:
find /project/directory -iname '*.php' -or -iname '*.phtml' | grep -iv '/some/directory' | xargs xgettext
我不能肯定地说find
是否存在 100% 有效的论点。 在一些头痛之后,使用grep
是一种快速简便的解决方案。
对于那些在旧版本 UNIX 上无法使用-path或-not的人
在 SunOS 5.10 bash 3.2 和 SunOS 5.11 bash 4.4 上测试
find . -type f -name "*" -o -type d -name "*excluded_directory*" -prune -type f
how-to-use-prune-option-of-find-in-sh是Laurence Gonsalves关于-prune
如何工作的一个很好的答案。
这是通用解决方案:
find /path/to/search \
-type d \
\( -path /path/to/search/exclude_me \
-o \
-name exclude_me_too_anywhere \
\) \
-prune \
-o \
-type f -name '*\.js' -print
为避免多次输入/path/to/seach/
,请将find
包装在pushd .. popd
对中。
pushd /path/to/search; \
find . \
-type d \
\( -path ./exclude_me \
-o \
-name exclude_me_too_anywhere \
\) \
-prune \
-o \
-type f -name '*\.js' -print; \
popd
我尝试了上面的命令,但没有一个使用“-prune”的命令对我有用。 最终我用下面的命令试了一下:
find . \( -name "*" \) -prune -a ! -name "directory"
对于我需要它的工作方式,从根目录开始在所有服务器中查找landscape.jpg
并排除/var
目录中的搜索:
find / -maxdepth 1 -type d | grep -v /var | xargs -I '{}' find '{}' -name landscape.jpg
find / -maxdepth 1 -type d
列出/
中的所有目录
grep -v /var
从列表中排除 `/var'
xargs -I '{}' find '{}' -name landscape.jpg
执行任何命令,例如从列表中find
每个目录/结果
我认为自己是一个 bash 瘾君子,但是……在过去的 2 年里,还没有找到一个针对这个的 bash 用户友好的解决方案。 通过“用户友好”,我的意思是只需要一个电话,这不需要我记住复杂的语法+我可以使用与以前相同的 find 语法,因此以下解决方案最适合那些 ^^^
将此复制粘贴到您的 shell 中并获取 ~/.bash_aliases :
cat << "EOF" >> ~/.bash_aliases
# usage: source ~/.bash_aliases , instead of find type findd + rest of syntax
findd(){
dir=$1; shift ;
find $dir -not -path "*/node_modules/*" -not -path "*/build/*" \
-not -path "*/.cache/*" -not -path "*/.git/*" -not -path "*/venv/*" $@
}
EOF
当然,为了添加或删除要排除的目录,您必须使用您选择的目录编辑此别名函数...
使用多个模式时的另一个示例-o -name
在根目录/
中搜索所有*.tpl
、 *.tf
文件,不包括位于/src/.terraform/
和/code/
中的文件。
$ find / -type f \( -name '*.tf' -o -name '*.tpl' \) \
-and \( -not -path '/src/.terraform/*' -and -not -path '/code/*' \)
/src/debug.tf
/src/nodegroup-infra.tpl
/src/variables.tf.tpl
我用hyperfine测试了上面的命令; 测试是在具有 3k 目录和 12k 文件的系统上进行的。 我认为可以公平地说它足够快~70ms
Benchmark #1: ./entrypoint.sh
Time (mean ± σ): 69.2 ms ± 1.4 ms [User: 22.6 ms, System: 43.6 ms]
Range (min … max): 66.4 ms … 72.2 ms 42 runs
/code/目录树
bash-5.0# tree /code
/code
├── debug.tf
├── entrypoint.sh
├── nodegroup-infra.tpl
├── tftemplate.sh
└── variables.tf.tpl
0 directories, 5 files
/src/目录树
bash-5.0# tree /src
/src
├── Dockerfile
├── debug.tf
├── entrypoint.sh
├── nodegroup-infra.tpl
├── terraform.tfstate
├── terraform.tfstate.backup
└── variables.tf.tpl
0 directories, 7 files
/根目录树总结
$ tree /
...
3382 directories, 12164 files
你也可以使用
find -type f -not -name .directoryname -printf "%f\n"
如果有人想在 Makefile 中添加 find 命令,这里是我们排除目录的方法
! -path "*/directoryName/*"
下面是格式化所有 golang 文件的示例,不包括 protobuf go 文件和 vendor 目录下的所有文件:
find . ! -name '*.pb.go' -name '*.go' ! -path "*/vendor/*" -exec gofmt -s -w '{}' +
如果您正在寻找高性能的答案,那么它是:
find . -type d -name node_modules -prune -false -o -type f
使用
-false
排除 node_modules 本身。
在 node_modules 中有 10000 个文件的目录中,它将比-not -path
方法快 3 倍。
find . -type f -not -path '*node_modules*'
如果 node_modules 有更多的文件,你将获得更高的性能。
这是有效的,因为find
测试模式“ *foo* ”的文件:
find ! -path "dir1" ! -path "dir2" -name "*foo*"
但如果您不使用模式( find
不测试文件),它就不起作用。 所以find
没有使用它以前评估过的“真”和“假”布尔值。 使用上述符号不工作的用例示例:
find ! -path "dir1" ! -path "dir2" -type f
没有find
测试! 因此,如果您需要查找没有任何模式匹配的文件,请使用 -prune。 此外,通过使用 prune find
总是更快,而它确实跳过该目录而不是匹配它或者最好不匹配它。 所以在这种情况下使用类似的东西:
find dir -not \( -path "dir1" -prune \) -not \( -path "dir2" -prune \) -type f
或者:
find dir -not \( -path "dir1" -o -path "dir2" -prune \) -type f
问候
我在 C 源文件中找到了函数名称 exclude *.o 和 exclude *.swp 和 exclude (不是常规文件)并使用以下命令排除 dir 输出:
find . \( ! -path "./output/*" \) -a \( -type f \) -a \( ! -name '*.o' \) -a \( ! -name '*.swp' \) | xargs grep -n soc_attach
使用exec
动作比使用for
循环更好:
find . -path "./dirtoexclude" -prune \
-o -exec java -jar config/yuicompressor-2.4.2.jar --type js '{}' -o '{}' \;
exec ... '{}' ... '{}' \;
将为每个匹配的文件执行一次,将大括号'{}'
替换为当前文件名。
请注意,大括号括在单引号中,以防止将它们解释为 shell 脚本标点符号* 。
*来自find (GNU findutils) 4.4.2
手册页的示例部分
对于FreeBSD用户:
find . -name '*.js' -not -path '*exclude/this/dir*'
如果搜索目录有模式(在我的情况下大部分时间); 你可以像下面这样简单地做:
find ./n* -name "*.tcl"
在上面的例子中; 它在所有以“n”开头的子目录中搜索。
我在这个页面上找到了建议,而且很多其他页面在我的 Mac OS X 系统上都不起作用。 但是,我发现了一个对我有用的变体。
最大的想法是搜索 Macintosh HD,但避免遍历所有外部卷,这些卷主要是 Time Machine 备份、映像备份、已安装的共享和存档,但不必全部卸载它们,这通常是不切实际的。
这是我的工作脚本,我将其命名为“findit”。
#!/usr/bin/env bash
# inspired by http://stackoverflow.com/questions/4210042/exclude-directory-from-find-command Danile C. Sobral
# using special syntax to avoid traversing.
# However, logic is refactored because the Sobral version still traverses
# everything on my system
echo ============================
echo find - from cwd, omitting external volumes
date
echo Enter sudo password if requested
sudo find . -not \( \
-path ./Volumes/Archive -prune -o \
-path ./Volumes/Boot\ OS\ X -prune -o \
-path ./Volumes/C \
-path ./Volumes/Data -prune -o \
-path ./Volumes/jas -prune -o \
-path ./Volumes/Recovery\ HD -prune -o \
-path ./Volumes/Time\ Machine\ Backups -prune -o \
-path ./Volumes/SuperDuper\ Image -prune -o \
-path ./Volumes/userland -prune \
\) -name "$1" -print
date
echo ============================
iMac2:~ jas$
各种路径与外部存档卷、Time Machine、虚拟机、其他安装的服务器等有关。 一些卷名中有空格。
一个好的测试运行是“findit index.php”,因为该文件出现在我系统上的许多地方。 使用此脚本,搜索主硬盘大约需要 10 分钟。 如果没有这些排除,则需要很多小时。
不确定这是否会涵盖所有边缘情况,但以下将非常直接且易于尝试:
ls -1|grep -v -e ddl -e docs| xargs rm -rf
这应该从当前目录 excpet 'ddls' 和 'docs' 中删除所有文件/目录。
代替:
for file in $(find . -name '*.js')
do
java -jar config/yuicompressor-2.4.2.jar --type js $file -o $file
done
...并且由于您没有定义要排除的子目录,因此可以使用:
for file in $(find *.js -maxdepth 0 -name '*.js')
do
java -jar config/yuicompressor-2.4.2.jar --type js $file -o $file
done
此语法将排除所有子目录。
看看下面的例子:在我的 tmp 目录下,我有一个巨大的“存档”子目录,其中包含 17000-4640=12360 个文件。 这个目录位于一个慢速 NFS 上。 虽然第一种语法扫描“存档”子目录并且性能不佳,但第二种语法仅扫描我当前目录中包含的“*pdf”文件并执行......还不错。
[tmp]$ time (find . -name "*pdf" | wc -l)
17000
real 0m40.479s
user 0m0.423s
sys 0m5.606s
[tmp]$ time (find *pdf -maxdepth 0 -name "*pdf" | wc -l)
4640
real 0m7.778s
user 0m0.113s
sys 0m1.136s
第二种语法非常有趣:在下面的示例中,我想检查文件 or60runm50958.pdf 是否存在并且超过 20 分钟。 亲自看看第二种语法如何更有效。 这是因为它避免扫描存档子目录。
[tmp]$ time find . -name or60runm50958.pdf -mmin +20
./or60runm50958.pdf
real 0m51.145s
user 0m0.529s
sys 0m6.243s
[tmp]$ time find or60runm50958.pdf -maxdepth 0 -name or60runm50958.pdf -mmin +20
or60runm50958.pdf
real 0m0.004s
user 0m0.000s
sys 0m0.002s
我想知道目录的数量,文件的数量只有当前目录的 MB - 而该代码正是我想要的:-)
来源
- ... 2791037 Jun 2 2011 foo.jpg
- ... 1284734651 Mär 10 16:16 foo.tar.gz
- ... 0 Mär 10 15:28 foo.txt
d ... 4096 Mär 3 17:12 HE
d ... 4096 Mär 3 17:21 KU
d ... 4096 Mär 3 17:17 LE
d ... 0 Mär 3 17:14 NO
d ... 0 Mär 3 17:15 SE
d ... 0 Mär 3 17:13 SP
d ... 0 Mär 3 17:14 TE
d ... 0 Mär 3 19:20 UN
编码
format="%s%'12d\n"
find . -type d -not -path "./*/*" | wc -l | awk -v fmt=$format '{printf fmt, " Anzahl Ordner = ", $1-1}'
find . -type f -not -path "./*/*" | wc -l | awk -v fmt=$format '{printf fmt, " Anzahl Dateien = ", $1}'
du . -hmS --max-depth=0 | awk -v fmt=$format '{printf fmt, " Groesse (MB) = ", $1}'
注意:额外的format="%s%'12d\n"
是awk
格式化数字所必需的。
结果
Anzahl Ordner = 8
Anzahl Dateien = 3
Groesse (MB) = 1.228
#find command in linux def : find command used to locate /search files in unix /linux system , find search for files in a directory hierarchy
1)exec Show diagnostic information relating to -exec, -execdir, -ok and -okdir 2)-options -H =do not follow symoblic links while except while procesing . -L = follow symbolic links -P =never follow symbolic links -type c File is of type c: b block (buffered) special c character (unbuffered) special d directory p named pipe (FIFO) f regular file l symbolic link; this is never true if the -L option or the -follow option is in effect, unless the symbolic link is broken. If you want to search for symbolic links when -L is in effect, use -xtype. s socket D door (Solaris) -Delete Delete files; true if removal succeeded. If the removal failed, an error message is issued. If -delete #fails, find's exit status will be nonzero (when it eventually exits). find /home/mohan/a -mindepth 3 -maxdepth 3 -type f -name "*.txt" |xargs rm -rf find -type d -name find -type f -Name find /path/ -type f -iname (i is case insenstive) #find directores a/b/c and only delete c directory inside have "*.txt " find /home/mohan/a -mindepth 3 -maxdepth 3 -type f -name "*.txt" |xargs rm -rf find /home/mohan/a -mindepth 3 -maxdepath 3 -type f -name "*.txt" -delete #delete particular directory have empty file and only we can delete empty files find /home/mohan -type f -name "*.txt" -empty -DELETE #find multiple files and also find empty files find /home/mohan -type f \( -name "*.sh" -o -name "*.txt" \) -empty #delete empty files two or more Files find /home/mohan -type f \( -nmae "*.sh" -o -name "*.txt" \) -empty -delete #How to append contents of multiple files into one file find . -type f -name '*.txt' -exec cat {} + >> output.file #last modified files finding using less than 1 min (-n) ls -lrth|find . -type f -mmin -1 #last modified files more than 1 min (+n) ls -lrth|find . -type f -mmin +1 #last modified files exactly one mins find . -type f -mmin 1 last modifiedfiles exactly in one day by using command (-mtime) find . -type f -mtime 10 #last modified more than 10 days find . -type f -mtime +10 #last modified less than 10 days find . -type f -mtime -10 #How to Find Modified Files and Folders Starting from a Given Date to the Latest Date find . -type f -newermt "17-11-2020" #How to Find a List of “sh” Extension Files Accessed in the Last 30 Days--- -matdimtype ls -lrt|find . -type f -iname ".sh" -atime -30 #How to Find a List of Files Created Today, -1 means less than min, ls -lrt | find . -type f -ctime -1 -ls
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.