hel*_*on3 1250 linux shell find
我正在尝试find为所有JavaScript文件运行命令,但如何排除特定目录?
这是find我们正在使用的代码.
for file in $(find . -name '*.js')
do
java -jar config/yuicompressor-2.4.2.jar --type js $file -o $file
done
Run Code Online (Sandbox Code Playgroud)
Get*_*ree 1839
如果-prune不适合你,这将:
find -name "*.js" -not -path "./directory/*"
Run Code Online (Sandbox Code Playgroud)
f10*_*bit 1002
使用剪枝开关,例如,如果要排除-prune目录,只需misc在find命令中添加一个:
find . -path ./misc -prune -o -name '*.txt' -print
Run Code Online (Sandbox Code Playgroud)
这是一个包含多个目录的示例:
find . -type d \( -path dir1 -o -path dir2 -o -path dir3 \) -prune -o -print
Run Code Online (Sandbox Code Playgroud)
这里我们排除dir1,dir2和dir3,因为在-path ./misc -prune -o表达式中它是一个动作,它作用于条件find(如果dir1或dir2或dir3),ANDed与-path dir1 -o -path dir2 -o -path dir3.进一步的行动是type -d,打印.
Dan*_*ral 434
我发现以下比其他提出的解决方案更容易推理:
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
Run Code Online (Sandbox Code Playgroud)
这来自一个实际的用例,我需要在wintersmith生成的一些文件上调用yui-compressor,但是遗漏了需要按原样发送的其他文件.
在里面-path并且find是一个完全 匹配的表达式find /full/path/ -not \( -path /full/path/exclude/this -prune \) ...(例如,如果您这样做将不匹配\(- \)在这种情况下您需要更改它),并且在成功时将避免遍历下面的任何内容.然后将其分组为具有转义括号的单个表达式,并以前缀build/external为其将-not跳过与该表达式匹配的任何内容.
有人可能会问,添加find是否会-not重新出现隐藏所有其他文件,答案是否定的.方法的-prune工作原理是,一旦到达,该目录下的文件将被永久忽略.
这也很容易扩展,以添加额外的排除.例如:
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
Run Code Online (Sandbox Code Playgroud)
Rei*_*ase 200
这里显然有一些混淆,即跳过目录的首选语法应该是什么.
GNU意见
To ignore a directory and the files under it, use -prune
Run Code Online (Sandbox Code Playgroud)
推理
-prune停止find下降到目录.只是指定-not -path仍将下降到跳过的目录中,但-not -path每次find测试每个文件时都将为false .
问题 -prune
-prune 做它的目的,但仍然是你在使用它时需要注意的一些事情.
find 打印已修剪的目录.
-prune只能使用-print而不能使用其他操作.
-prune适用于除以外的任何操作-delete.为什么删除不起作用?为了-delete工作,找到需要以DFS顺序遍历目录,因为-delete将首先删除叶子,然后删除叶子的父类等...但是为了指定-prune有意义,find需要命中一个目录并停止下降它,显然是没有意义的有-depth或-delete上.性能
我设置了三大顶尖upvoted答案的一个简单的测试,在这个问题上(替换-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
Run Code Online (Sandbox Code Playgroud)
结论
无论f10bit的语法和丹尼尔C.索布拉尔的语法了10-25ms,以平均运行.GetFree的语法,不使用-prune,花了865ms.所以,是的,这是一个相当极端的例子,但如果你关心运行时间并且正在做任何远程密集的事情你应该使用-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
Run Code Online (Sandbox Code Playgroud)
Gab*_*les 97
在 Linux Ubuntu 18.04、20.04 和 22.04 中测试。
\nfind非常重要和强大,但又如此微妙和令人困惑!
\n\n\n
*.js使用 搜索文件时如何排除特定目录find?
这是一个非常有用的例子,它没有直接回答OP的问题,但在我看来更有用:
\n@Kamil Dziedzic在我的答案下面的评论中提问(已更正语法和标点符号):
\n\n\n如何忽略具有给定前缀的目录?例如,我想排除以
\n_.
具体方法如下:
\n# Ignore all directories (and their contents, via `-prune`) beginning with\n# prefix "prefix" at the lowest level of the specified directory (`.`). \nfind . -not \\( -path "./prefix*" -type d -prune \\) | sort -V\n\n# Ignore all directories (and their contents, via `-prune`) beginning with\n# prefix "prefix" at any level recursively within the specified directory.\nfind . -not \\( -path "*/prefix*" -type d -prune \\) | sort -V\nRun Code Online (Sandbox Code Playgroud)\n因此,对于 目录前缀_,请使用您想要的其中一个:
find . -not \\( -path "./_*" -type d -prune \\) | sort -V\nfind . -not \\( -path "*/_*" -type d -prune \\) | sort -V\nRun Code Online (Sandbox Code Playgroud)\n解释:
\n.意思是“当前目录”*是find通配符,匹配任意数量的任意字符(如正则表达式.*)\\(和\\)是转义括号。它们必须用反斜杠转义,以便它们find作为参数传递给find而不是由您的 shell 解释器本身处理(例如bash或sh或您使用的任何 shell)-not \\( \\)表示忽略与括号内的条件匹配的文件。-path "./prefix*"表示匹配以 开头的所有路径./prefix,这意味着位于.您在find命令中指定的目录的最低级别的所有路径。-path "*/prefix*"将匹配以任何内容开头,后跟 的所有路径/prefix,表示prefix搜索路径中任何目录中任何级别以任何级别开头的任何路径。-type d说只匹配d目录。这将与刚刚指定的内容进行“与”运算-path,使其仅匹配以指定前缀开头且类型为“目录”的文件。-prune表示不要遍历到匹配的目录。来自man find:“如果文件是目录,则不要进入它。 ”因此,如果没有该选项-prune,目录./prefixWhateverDir本身将被排除,但该目录中的./prefixWhateverDir/file1.c文件和文件不会被排除(甚至不会被排除-也因为它们不属于)。添加可以避免遍历到排除的目录,从而也排除该目录中的文件。这可能看起来很奇怪,但请记住,在 Linux 和 Unix 系统中,目录也是“文件”,只是特殊类型的文件,可以作为其他文件路径中的前缀。因此,考虑到这一点,必须使用就更有意义了。./prefixWhateverDir/file2.c ./prefixWhateverDir/prefixFile1.c./prefixWhateverDir/prefixFile2.c-type d-prune-prunesort -Vwith| sort -V只是对输出进行排序,使其按字母顺序排列即可。如果您认为-not 或 -prune是必需的,但不是两者兼而有之,那就是不正确的。-not请参阅下面我刚刚添加的名为“解决其他注释”的新部分,以查看使用and -prune、 only-not和 only运行上述命令的详细示例-prune。它们不是同一件事。
这直接回答了OP的问题。
\n遵循这些模式。另请参阅我的评论。这些是我发现的最好、最有效的模式。转义括号 ( \\(and \\)) 和-prune选项对于速度非常重要。请阅读下文以了解原因。
最佳使用模式:
\n-name \'*.js\'当然,如果您正在寻找通用答案而不是试图解决OP的原始问题(其中还涉及仅查找.js名称中带有扩展名的文件),请删除下面每个命令的部分。
# Exclude one path, and its contents, saving time by *not* recursing down the\n# excluded path at all.\nfind . -name \'*.js\' -not \\( -path "./dir_to_exclude" -prune \\)\n\n# Add the wildcard asterisk (`*`) to the end of the match pattern, as\n# in "./dir_to_exclude*", to exclude all files & folders beginning with the\n# name `./dir_to_exclude`. Prune to save time by *not* recursing down the\n# excluded paths at all.\n# - You can add the asterisk to the end of the pattern to apply this pattern to\n# all examples below as well, if desired.\n# - This example pattern would exclude "./dir_to_exclude", "./dir_to_exclude1",\n# "./dir_to_exclude2", "./dir_to_exclude99", "./dir_to_exclude_some_long_name",\n# "./dir_to_exclude_another_long_name", etc., as well as exclude all **files**\n# beginning with this match pattern but not otherwise in an excluded dir.\nfind . -name \'*.js\' -not \\( -path "./dir_to_exclude*" -prune \\)\n\n# Exclude multiple paths and their contents, saving time by *not* recursing down\n# the excluded paths at all.\nfind . -name \'*.js\' \\\n -not \\( -path "./dir_to_exclude1" -prune \\) \\\n -not \\( -path "./dir_to_exclude2" -prune \\) \\\n -not \\( -path "./dir_to_exclude3" -prune \\)\n\n\n# If you change your "starting point" path from `.` to something else, be sure\n# to update the beginning of your `-path` with that as well, like this:\n\nfind "some_dir" -name \'*.js\' -not \\( -path "some_dir/dir_to_exclude" -prune \\)\n\nfind "some_dir" -name \'*.js\' \\\n -not \\( -path "some_dir/dir_to_exclude1" -prune \\) \\\n -not \\( -path "some_dir/dir_to_exclude2" -prune \\) \\\n -not \\( -path "some_dir/dir_to_exclude3" -prune \\)\nRun Code Online (Sandbox Code Playgroud)\n上面的模式是最好的,因为当选项-prune使用转义括号打开时(如上所示),并且当您指定这样的文件夹名称(在本例中文件夹名称后面没有任何内容)时,它会排除该文件夹及其内容。
如果删除括号和-prune选项,-not -path "./dir_to_exclude"将仅排除目录名称,而不排除其内容。如果您不遵循我上面推荐的模式,则必须使用-not -path "./dir_to_exclude"仅排除文件夹名称、-not -path "./dir_to_exclude/*"仅排除文件夹内容和-not -path "./dir_to_exclude" -not -path "./dir_to_exclude/*"排除两者。
-prune此外,从上面的示例中删除括号和选项需要花费2 倍~100 倍的时间。这是一个巨大的速度差异!使用括号和-prune选项会导致find不向下递归排除的目录,但find . -not -path "./dir_to_exclude" -not -path "./dir_to_exclude/*"仍会浪费大量时间向下递归排除的目录。
使用时find:
您必须在尝试匹配的路径中包含通配符 ( *) 或“起点”路径。-path例子:
通过添加前缀 your 来与“起点”路径匹配,-path匹配相对于“起点”路径的精确路径:
# 1. with the "starting point" being the current directory, `.`\nfind . -not -path "./dir_to_exclude/*"\n# or (same thing)\nfind -not -path "./dir_to_exclude/*"\n\n# 2. with the "starting point" being the root dir, `/`\nfind / -not -path "/dir_to_exclude/*"\n\n# 3. with the "starting point" being "some_dir"\nfind "some_dir" -not -path "some_dir/dir_to_exclude/*"\nRun Code Online (Sandbox Code Playgroud)\n再次注意,在上面的所有 -path匹配中,您必须显式地使用“起点”路径作为路径前缀。否则,您可以使用通配符:
匹配通配符路径以在搜索路径中的任何级别或子目录-path中查找您的路径。即:在您的前面加上前缀. 例子:-path*
# match "./dir_to_exclude/file1" as well as \n# "./another_dir/dir_to_exclude/file1"\nfind . -not -path "*/dir_to_exclude/*"\n\n# match "/dir_to_exclude/file1" as well as \n# "/another_dir/dir_to_exclude/file1"\nfind / -not -path "*/dir_to_exclude/*"\n\n# match "some_dir/dir_to_exclude/file1" as well as \n# "some_dir/another_dir/dir_to_exclude/file1"\nfind "some_dir" -not -path "*/dir_to_exclude/*"\nRun Code Online (Sandbox Code Playgroud)\n再次注意,在上面的所有 -path匹配中,我明确地使用通配符作为路径前缀,*以在任何级别进行匹配。
用于-ipath进行不区分大小写的路径匹配。从man find:
\n\nRun Code Online (Sandbox Code Playgroud)\n-ipath pattern\n Like -path. but the match is case insensitive.\n
例子:
\n-ipath pattern\n Like -path. but the match is case insensitive.\nRun Code Online (Sandbox Code Playgroud)\n当不使用转义括号和-prune选项时,find仍然会沿着排除的路径递归,使其像泥一样慢。\xe2\x98\xb9\xef\xb8\x8f
当不使用转义括号和-prune选项时,find . -not -path "./dir_to_exclude/*"仅排除排除的目录的内容find . -not -path "./dir_to_exclude",但不排除排除的目录本身,并且仅排除目录名称本身,但不排除该目录中的内容(文件和文件夹)!使用两者来排除两者。例子:
# exclude "./dir_to_exclude/*", as well as "./DIR_TO_EXCLUDE/*", and \n# "./DiR_To_eXcluDe/*", etc.\nfind . -not -ipath "./dir_to_exclude/*"\nRun Code Online (Sandbox Code Playgroud)\n“经验法则”部分中的所有上述示例都是纯粹的垃圾和垃圾 \xe2\x98\xb9\xef\xb8\x8f。我是在开玩笑和夸大其词,但重点是:我认为它们远没有那么好,原因已解释。您应该用转义括号和选项将它们中的每一个包裹起来-prune,如下所示:
# exclude the files and folders within the excluded dir, but\n# leaving "./dir_to_exclude" itself\nfind . -not -path "./dir_to_exclude/*"\n\n# exclude the dir name only, but leaving (NOT excluding) all files and\n# folders within that dir!\nfind . -not -path "./dir_to_exclude"\n\n# exclude both the folder itself, as well as its contents\nfind . \\\n -not -path "./dir_to_exclude/*" \\\n -not -path "./dir_to_exclude"\nRun Code Online (Sandbox Code Playgroud)\n选择-prune真的很重要。这就是它的含义,来自man find(强调):
\n\n\n
-prune真的; 如果该文件是目录,则不要进入该目录。如果-depth给出,则\n-prune无效。因为-delete暗示-depth,你不能有效地将-prune\nand-delete一起使用。例如,要跳过目录
\nsrc/emacs以及 \nit 下的所有文件和目录,并打印找到的其他文件的名称,请执行以下操作:Run Code Online (Sandbox Code Playgroud)\nfind . -not \\( -path "./dir_to_exclude/*" -prune \\)\nfind -not \\( -path "./dir_to_exclude/*" -prune \\)\nfind / -not \\( -path "/dir_to_exclude/*" -prune \\)\nfind "some_dir" -not \\( -path "some_dir/dir_to_exclude/*" -prune \\)\n\nfind . -not \\( -path "*/dir_to_exclude/*" -prune \\)\nfind / -not \\( -path "*/dir_to_exclude/*" -prune \\)\nfind "some_dir" -not \\( -path "*/dir_to_exclude/*" -prune \\)\n\nfind . -not \\( -ipath "./dir_to_exclude/*" -prune \\)\n\nfind . -not \\( -path "./dir_to_exclude/*" -prune \\)\nfind . -not \\( -path "./dir_to_exclude" -prune \\)\nfind . \\\n -not \\( -path "./dir_to_exclude/*" -prune \\) \\\n -not \\( -path "./dir_to_exclude" -prune \\)\n
上面的内容是我截至 2022 年 9 月 4 日的最新信息。下面的内容是我的旧答案,其中仍然有大量有用的信息,但没有涵盖细微差别以及我上面介绍的内容。阅读它以获取更多知识并查看更多示例,将您在上面学到的内容应用到我下面介绍的内容中。
\n请注意,要排除的文件夹名称之前的./(或*/,请参见下面)和之后的(或,但请参见下面的警告)是必需的,以便排除及其中的任何内容!/**dir_to_exclude
另外,为了提高速度,并且不遍历排除的目录,请注意非常重要的转义分组括号和-prune选项。前任:find -not \\( -path "*/dir_to_exclude/*" -prune \\)。
要在手册页中查看这些转义分组括号的示例,请运行man find,然后按/进行搜索。\\(例如,使用正则表达式pattern搜索pattern \\\\\\(。按Enter开始搜索手册页。搜索时按N“下一个匹配”。
这些工作:
\nfind . -path ./src/emacs -prune -o -print\nRun Code Online (Sandbox Code Playgroud)\n[使用这些]这些也有效,而且更好,因为它们导致 find 不会不必要地遍历排除的路径!:
\n (这在速度上产生了巨大的差异(快了 2 倍~100 倍)!请参见此处和此处。您也可以分别使用转义搜索man find字符串\\(和,在本地搜索页面中的字符串和)。\\)\\\\\\(\\\\\\)
# [my favorite #1] exclude contents of `dir_to_exclude` at the search root\nfind -not -path "./dir_to_exclude/*"\n\n# exclude all files & folders beginning with the name `dir_to_exclude` at the\n# search root \nfind -not -path "./dir_to_exclude*"\n\n# [my favorite #2] exclude contents of `dir_to_exclude` at any level within your\n# search path\nfind -not -path "*/dir_to_exclude/*"\n\n# exclude all files & folders beginning with the name `dir_to_exclude` at any\n# level within your search path\nfind -not -path "*/dir_to_exclude*"\n\n# To exclude multiple matching patterns, use `-not -path "*/matching pattern/*"`\n# multiple times, like this\nfind -not -path "*/dir_to_exclude1/*" -not -path "*/dir_to_exclude2/*"\nRun Code Online (Sandbox Code Playgroud)\n...但这些不起作用:
\nfind -not \\( -path "./dir_to_exclude" -prune \\) # works to exclude *both* the \n # directory *and* its contents\n # here, here but does *not*\n # exclude the contents as well\n # when the directory name is\n # written like this in the\n # examples above\nfind -not \\( -path "./dir_to_exclude*" -prune \\)\nfind -not \\( -path "./dir_to_exclude/*" -prune \\)\nfind -not \\( -path "*/dir_to_exclude" -prune \\) # same note as just above\nfind -not \\( -path "*/dir_to_exclude*" -prune \\)\nfind -not \\( -path "*/dir_to_exclude/*" -prune \\)\n\n# To exclude multiple matching patterns at once, use the `-not \\( ... \\)` \n# pattern multiple times, like this\nfind -not \\( -path "*/dir_to_exclude1/*" -prune \\) \\\n -not \\( -path "*/dir_to_exclude2/*" -prune \\)\nRun Code Online (Sandbox Code Playgroud)\n关键是,通常,要使其正常工作,您必须以或开始每个匹配模式,并以或结束每个匹配模式,具体取决于您想要实现的目标。./*//**我说“一般”,是因为上面的 -style 部分有两个值得注意的例外情况-not \\( ... \\)。您可以通过它们右侧的注释来识别这两个例外:# works here but not above。
dir_to_exclude您正在搜索的根目录中的所有文件和文件夹。\n请注意,这会排除 中的所有子文件和子文件夹dir_to_exclude,但不会排除dir_to_exclude目录本身。\n# These do NOT work!\nfind -not -path "dir_to_exclude"\nfind -not -path "dir_to_exclude/*"\nfind -not -path "./dir_to_exclude"\nfind -not -path "./dir_to_exclude/"\nRun Code Online (Sandbox Code Playgroud)\ndir_to_excludedir 本身(以及名称以这些字符开头的任何文件或文件夹)。\n警告:这也排除dir_to_exclude1、dir_to_exclude2、dir_to_exclude_anyTextHere等。它排除仅以文本开头dir_to_exclude且位于根目录中的任何文件或文件夹您正在搜索的目录。\nfind -not \\( -path "./dir_to_exclude/*" -prune \\)\nRun Code Online (Sandbox Code Playgroud)\n*只需在路径前面添加通配符,而不是使用.来指示搜索根目录。\nfind -not \\( -path "./dir_to_exclude*" -prune \\)\nRun Code Online (Sandbox Code Playgroud)\ndir_to_exclude find -not \\( -path "*/dir_to_exclude/*" -prune \\)\nRun Code Online (Sandbox Code Playgroud)\n在 中./,开头的 表示“从当前目录.开始”(或者在 中,是一个通配符,用于选取到目前为止的任何字符),而在结尾处, 是一个通配符,用于选取 中的任何字符字符后面的路径字符串。这意味着以下内容:*/*/**/
"./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:
find -not \\( -path "*/dir_to_exclude*" -prune \\)\nRun Code Online (Sandbox Code Playgroud)\n要排除多个匹配模式,只需使用-not \\( -path "*/matching pattern/*" -prune \\)多次即可。前任:
# Case-sensitive; notice I use `\\.` instead of `.` when grepping, in order to\n# search for the literal period (`.`) instead of the regular expression\n# wildcard char, which is also a period (`.`).\nfind -not \\( -path "./dir_to_exclude/*" -prune \\) \\\n | grep "desired_file_name\\.txt"\n\n# Case-INsensitive (use `-i` with your `grep` search)\nfind -not \\( -path "./dir_to_exclude/*" -prune \\) \\\n | grep -i "desired_file_name\\.txt"\n\n# To make `dir_to_exclude` also case INsensitive, use the `find` `-ipath` option\n# instead of `-path`:\nfind -not -ipath \\( -path "./dir_to_exclude/*" -prune \\) \\\n | grep -i "desired_file_name\\.txt"\nRun Code Online (Sandbox Code Playgroud)\n我在这里使用上面的示例作为我的sublf别名的一部分(更新:该别名正在扩展并移动到此处此文件夹中的sublf.sh脚本中)。这个别名允许我使用模糊查找器在 Sublime Text 中快速搜索并打开多个文件。请参阅上面的链接以获取其最新版本。fzf
# Exclude all ".git" and "..git" dirs at any level in your search path\nfind -not \\( -path "*/.git/*" -prune \\) -not \\( -path "*/..git/*" -prune \\)\nRun Code Online (Sandbox Code Playgroud)\n-prune都-not需要才能得到想要的效果来自 @Ritin 的评论(已修复格式/措辞):
\n\n\n@Gabriel Staples,两者
\n-not都不-prune是必需的。使用-prune或-not:find . \\( -path \'*frontend*\' -o -path \'*/\\.*\' -o -path "*node_modules*" \\) -prune -o -type f |sort -V
我的回复:
\n@Ritin,那是不正确的。为了达到我想要的效果, 和-not都是-prune必需的。这正是我在回答开头所说的内容:
\n\n\n
find非常重要和强大,但又如此微妙和令人困惑!
在我的eRCaGuy_hello_world/cpp/文件夹中运行以下示例以查看差异:
\n两者-not和-prune:
命令和输出:
\nalias sublf=\'FILES_SELECTED="$(find -not \\( -path "*/.git/*" -prune \\) \\\n-not \\( -path "*/..git/*" -prune \\) \\\n| fzf -m)" \\\n&& echo "Opening these files in Sublime Text:" \\\n&& echo "$FILES_SELECTED" \\\n&& subl $(echo "$FILES_SELECTED")\'\nRun Code Online (Sandbox Code Playgroud)\n正如您所看到的,此命令只留下一个文件:./template_non_type_template_params_print_int_TODO.cpp. 它会删除路径中以 开头的所有目录./template,以及其中的所有内容(文件和文件夹)。这就是我想要的效果。
-not仅有的:
命令和输出:
\neRCaGuy_hello_world/cpp$ find . -not \\( -path "./template*" -type d \\) | sort -V | grep -i \'\\./template\'\n./template_function_sized_array_param/print_array_calls_by_array_size.ods\n./template_function_sized_array_param/readme.md\n./template_function_sized_array_param/regular_func\n./template_function_sized_array_param/regular_func.cpp\n./template_function_sized_array_param/template_func\n./template_function_sized_array_param/template_func.cpp\n./template_non_type_template_params_print_int_TODO.cpp\n./template_practice/explicit_template_specialization.cpp\n./template_practice/research/B
Jos*_*hua 60
一种选择是使用grep排除包含目录名称的所有结果.例如:
find . -name '*.js' | grep -v excludeddir
Run Code Online (Sandbox Code Playgroud)
Dim*_*Dak 59
这是唯一一个对我有用的人.
find / -name MyFile ! -path '*/Directory/*'
Run Code Online (Sandbox Code Playgroud)
搜索"NameOfFile",不包括"目录".强调星星*.
mpa*_*pis 41
我更喜欢这种-not符号......它更具可读性:
find . -name '*.js' -and -not -path directory
Run Code Online (Sandbox Code Playgroud)
Dre*_*ell 20
使用-prune选项.所以,像:
find . -type d -name proc -prune -o -name '*.js'
Run Code Online (Sandbox Code Playgroud)
'-type d -name proc -prune'仅查找名为proc的目录以进行排除.
'-o'是'OR'运算符.
wis*_*cky 16
-prune肯定是有效的,是最好的答案,因为它可以防止下降到你想要排除的目录.-not -path仍然搜索排除的目录,它只是不打印结果,如果排除的目录是挂载网络卷或您没有权限,这可能是一个问题.
棘手的部分是find参数的顺序是非常特别的,所以如果你没有恰到好处,那么你的命令可能不起作用.参数的顺序通常是这样的:
find {path} {options} {action}
Run Code Online (Sandbox Code Playgroud)
{path}:首先放入所有与路径相关的参数,比如 . -path './dir1' -prune -o
{options}:-name, -iname, etc作为这个组中的最后一个选项,我获得了最大的成功.例如-type f -iname '*.js'
{action}:你想要-print在使用时添加-prune
这是一个有效的例子:
# 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
Run Code Online (Sandbox Code Playgroud)
小智 15
这是我用来排除某些路径的格式:
$ find ./ -type f -name "pattern" ! -path "excluded path" ! -path "excluded path"
Run Code Online (Sandbox Code Playgroud)
我用它来查找不在".*"路径中的所有文件:
$ find ./ -type f -name "*" ! -path "./.*" ! -path "./*/.*"
Run Code Online (Sandbox Code Playgroud)
tia*_*chn 12
如果您正在寻找高性能的答案,那么它是:
find . -type d -name node_modules -prune -false -o -type f
Run Code Online (Sandbox Code Playgroud)
用于
-false排除 node_modules 本身。
它比-not -path在 node_modules 中包含 10000 个文件的目录中的方法快 3 倍。
find . -type f -not -path '*node_modules*'
Run Code Online (Sandbox Code Playgroud)
如果node_modules有更多的文件,你将获得更高的性能。
Wol*_*ahl 10
-path -prune方法也适用于路径中的通配符.这是一个find语句,它将找到服务于多个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 \)
Run Code Online (Sandbox Code Playgroud)
一个好的技巧,以避免打印修剪目录是使用-print(对于作品-exec的右侧后以及)-or之后-prune。例如, ...
find . -path "*/.*" -prune -or -iname "*.j2"
Run Code Online (Sandbox Code Playgroud)
将打印当前目录下所有扩展名为“.j2”的文件的路径,跳过所有隐藏目录。整洁。但它也会打印每个目录的完整路径,如上所述。但是,以下没有,...
find . -path "*/.*" -prune -or -iname "*.j2" -print
Run Code Online (Sandbox Code Playgroud)
因为从逻辑上讲-and,在-iname运算符之后和 -print 之前有一个隐藏。-or由于操作和关联的布尔顺序,这将它绑定到子句的右侧部分。但是文档说-print如果-print0没有指定它(或它的任何表亲 ...等),就会有一个隐藏。那么为什么不是-or打印的左侧部分呢?显然(从我第一次阅读手册页时我没有理解这一点),如果没有-print- 或-execANYWHERE,这是真的,在这种情况下, -print 逻辑上散布,以便打印所有内容。如果甚至一个print-style 操作在任何子句中表达,所有隐藏的逻辑操作都消失了,您只能获得您指定的内容。现在坦率地说,我可能更喜欢它的另一种方式,但是find只有描述性运算符的a显然什么都不做,所以我想它是有道理的。如上所述,这一切都适用-exec,所以下面给出了ls -la每个具有所需扩展名的文件的完整列表,但没有列出每个隐藏目录的第一级,...
find . -path "*/.*" -prune -or -iname "*.j2" -exec ls -la -- {} +
Run Code Online (Sandbox Code Playgroud)
对于我(以及此线程上的其他人),find语法很快就会变得非常巴洛克,所以我总是抛出括号以确保我知道什么绑定到什么,所以我通常为类型能力创建一个宏并将所有此类语句形成为 . ..
find . \( \( ... description of stuff to avoid ... \) -prune \) -or \
\( ... description of stuff I want to find ... [ -exec or -print] \)
Run Code Online (Sandbox Code Playgroud)
以这种方式将世界分为两部分,这样就不会出错。我希望这会有所帮助,尽管似乎任何人都不太可能阅读第 30 个以上的答案并投票,但可以希望。:-)
要排除多个目录:
find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" \)
Run Code Online (Sandbox Code Playgroud)
要添加目录,请添加-o -path "./dirname/*":
find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" -o -path "./dir3/*"\)
Run Code Online (Sandbox Code Playgroud)
但是,如果要排除许多目录,也许您应该使用正则表达式.
有很多好的答案,我花了一些时间来理解命令的每个元素是什么以及它背后的逻辑.
find . -path ./misc -prune -o -name '*.txt' -print
Run Code Online (Sandbox Code Playgroud)
find将开始在当前目录中查找文件和目录,因此find ..
该-o选项代表逻辑OR,并将命令的两个部分分开:
[ -path ./misc -prune ] OR [ -name '*.txt' -print ]
Run Code Online (Sandbox Code Playgroud)
任何不是 ./misc目录的目录或文件都不会通过第一次测试-path ./misc.但他们将针对第二个表达进行测试.如果他们的名字对应于*.txt他们打印的图案,因为-print选项.
当find到达./misc目录时,此目录仅满足第一个表达式.因此该-prune选项将适用于它.它告诉find命令不要探索该目录.因此,./misc中的任何文件或目录都不会被find探索,也不会针对表达式的第二部分进行测试,也不会被打印.
小智 7
对于工作解决方案(在Ubuntu 12.04(精确穿山甲)上测试)...
find ! -path "dir1" -iname "*.mp3"
Run Code Online (Sandbox Code Playgroud)
将在dir1子文件夹中搜索当前文件夹和子文件夹中的MP3文件.
使用:
find ! -path "dir1" ! -path "dir2" -iname "*.mp3"
Run Code Online (Sandbox Code Playgroud)
...排除dir1和dir2
find -name '*.js' -not -path './node_modules/*' -not -path './vendor/*'
Run Code Online (Sandbox Code Playgroud)
似乎与
find -name '*.js' -not \( -path './node_modules/*' -o -path './vendor/*' \)
Run Code Online (Sandbox Code Playgroud)
并且更容易记住 IMO。
您可以使用prune选项来实现此目的.例如:
find ./ -path ./beta/* -prune -o -iname example.com -print
Run Code Online (Sandbox Code Playgroud)
或者反grep"grep -v"选项:
find -iname example.com | grep -v beta
Run Code Online (Sandbox Code Playgroud)
您可以在Linux查找命令中找到详细说明和示例,从搜索中排除目录.
您还可以使用正则表达式来包含/排除某些文件 /dirs 您的搜索使用以下内容:
find . -regextype posix-egrep -regex ".*\.(js|vue|s?css|php|html|json)$" -and -not -regex ".*/(node_modules|vendor)/.*"
Run Code Online (Sandbox Code Playgroud)
这只会为您提供所有 js、vue、css 等文件,但不包括node_modules和vendor文件夹中的所有文件。
find . -name '*.js' -\! -name 'glob-for-excluded-dir' -prune
Run Code Online (Sandbox Code Playgroud)
以前的答案在 Ubuntu 上都不好。尝试这个:
find . ! -path "*/test/*" -type f -name "*.js" ! -name "*-min-*" ! -name "*console*"
Run Code Online (Sandbox Code Playgroud)
我在这里找到了这个
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/
??? ...
Run Code Online (Sandbox Code Playgroud)
该/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
Run Code Online (Sandbox Code Playgroud)
因此,每当我需要在我的/(根)分区上搜索文件时,我都需要处理(尽可能避免)遍历我的备份分区。
例子
在此线程(如何在 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!
Run Code Online (Sandbox Code Playgroud)
...认定,文件在短短的几秒钟,而这取多长(出现在所有的“排除”目录的递归):
## 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
Run Code Online (Sandbox Code Playgroud)
解决方案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
Run Code Online (Sandbox Code Playgroud)
总结 | 结论
使用“解决方案 1 ”中说明的方法
find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
Run Code Online (Sandbox Code Playgroud)
IE
... -path <excluded_path> -prune -o ...
Run Code Online (Sandbox Code Playgroud)
请注意,每当您将尾随添加/到排除的路径时,该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)
Run Code Online (Sandbox Code Playgroud)
排除嵌套目录:
在这里,我想排除嵌套目录,例如/mnt/Vancouver/projects/ie/claws/data/*从/mnt/Vancouver/projects/以下位置搜索时:
$ 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
Run Code Online (Sandbox Code Playgroud)
旁白:-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
Run Code Online (Sandbox Code Playgroud)
以下命令有效:
find . -path ./.git -prune -o -print
Run Code Online (Sandbox Code Playgroud)
如果您在查找时遇到问题,请使用该-D tree选项查看表达式分析信息。
find -D tree . -path ./.git -prune -o -print
Run Code Online (Sandbox Code Playgroud)
或者-D all, 查看所有执行信息。
find -D all . -path ./.git -prune -o -print
Run Code Online (Sandbox Code Playgroud)
find . \( -path '.**/.git' -o -path '.**/.hg' \) -prune -o -name '*.js' -print
Run Code Online (Sandbox Code Playgroud)
上面的例子查找*.js当前目录下的所有文件,不包括文件夹.git和.hg,不管这些.git和.hg文件夹有多深。
注意:这也有效:
find . \( -path '.*/.git' -o -path '.*/.hg' \) -prune -o -name '*.js' -print
Run Code Online (Sandbox Code Playgroud)
但我更喜欢使用**与其他一些工具保持一致的符号,这些工具在这里会偏离主题。
如果有人正在研究如何一次忽略多条路径。您可以使用 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
Run Code Online (Sandbox Code Playgroud)
同样出于某种原因,您将无法忽略 /bin/ 目录路径。
| 归档时间: |
|
| 查看次数: |
920891 次 |
| 最近记录: |