如何使用“-prune” “查找”选项在sh?

发布于 2024-08-05 13:49:39 字数 724 浏览 3 评论 0原文

我不太明白 man find 给出的例子,有人能给我一些例子和解释吗?我可以在其中结合正则表达式吗?


更详细的问题是这样的:

编写一个shell脚本,changeall,它有一个类似changeall [-r|-R]“string1”“string2”的接口。它将查找后缀为 .h.C.cc.cpp 的所有文件,并且将所有出现的 string1 更改为 string2-r 是仅保留在当前目录或包含子目录的选项。

注意:

  1. 对于非递归情况,不允许 ls,我们只能使用 findsed
  2. 我尝试了 find -depth 但它不受支持。这就是为什么我想知道 -prune 是否可以提供帮助,但不理解 man find 中的示例。

EDIT2:我正在做作业,我没有详细询问问题,因为我想自己完成它。既然我已经做完并交了,现在我可以陈述整个问题了。另外,我在不使用 -prune 的情况下成功完成了作业,但无论如何我还是想学习它。

I don't quite understand the example given from the man find, can anyone give me some examples and explanations? Can I combine regular expression in it?


The more detailed question is like this:

Write a shell script, changeall, which has an interface like changeall [-r|-R] "string1" "string2". It will find all files with an suffix of .h, .C, .cc, or .cpp and change all occurrences of string1 to string2. -r is option for staying in current dir only or including subdir's.

NOTE:

  1. For non-recursive case, ls is NOT allowed, we could only use find and sed.
  2. I tried find -depth but it was NOT supported. That's why I was wondering if -prune could help, but didn't understand the example from man find.

EDIT2: I was doing assignment, I didn't ask question in great details because I would like to finish it myself. Since I already done it and hand it in, now I can state the whole question. Also, I managed to finish the assignment without using -prune, but would like to learn it anyway.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

雅心素梦 2024-08-12 13:49:39

我发现 -prune 令人困惑的是它是一个操作(如 -print),而不是测试(如 -name) 。它会更改“待办事项”列表,但始终返回 true

使用 -prune 的一般模式是这样的:

find [path] [conditions to prune] -prune -o \
            [your usual conditions] [actions to perform]

您几乎总是希望在 -prune 之后紧接着 -o (逻辑或),因为这样测试的第一部分(直到并包括 -prune)将为您真正想要的东西(即:您不想要的东西返回false) em>想要修剪掉)。

这是一个示例:

find . -name .snapshot -prune -o -name '*.foo' -print

这将找到不在“.snapshot”目录下的“*.foo”文件。在此示例中,-name .snapshot 构成了[修剪条件]-name '*.foo' -print 为< code>[您的通常情况] 和 [要执行的操作]

重要说明

  1. 如果您只想打印结果,您可能会习惯省略-print 操作。使用 -prune 时,您通常不想这样做。

    如果除了 -prune-print 操作“与”整个表达式>(讽刺的是)最后。这意味着写这个:

    <前><代码> 查找 . -name .snapshot -prune -o -name '*.foo' # 不要这样做

    相当于这样写:

    <前><代码> 查找 . \( -name .snapshot -prune -o -name '*.foo' \) -print # 不要这样做

    这意味着它还会打印出您正在修剪的目录的名称,这通常不是您想要的。相反,如果您想要的话,最好显式指定 -print 操作:

    <前><代码> 查找 . -name .snapshot -prune -o -name '*.foo' -print # 执行此操作

  2. 如果您的“通常情况”恰好与也与您的修剪条件匹配的文件相匹配,则这些文件将不会 包含在输出中。解决此问题的方法是向剪枝条件添加 -type d 谓词。

    例如,假设我们想要删除任何以 .git 开头的目录(这无疑是有些人为的——通常您只需要删除名为的东西 .git),但除此之外还想查看所有文件,包括像 .gitignore 这样的文件。你可以试试这个:


    <前><代码>查找 . -name '.git*' -prune -o -type f -print # 不要这样做

    不会在输出中包含.gitignore。这是修复后的版本:

    <前><代码>查找 . -name '.git*' -type d -prune -o -type f -print # 这样做

额外提示:如果您使用 GNU 版本的 findfind 的 texinfo 页面比其联机帮助页有更详细的解释(对于大多数 GNU 实用程序来说也是如此)。

The thing I'd found confusing about -prune is that it's an action (like -print), not a test (like -name). It alters the "to-do" list, but always returns true.

The general pattern for using -prune is this:

find [path] [conditions to prune] -prune -o \
            [your usual conditions] [actions to perform]

You pretty much always want the -o (logical OR) immediately after -prune, because that first part of the test (up to and including -prune) will return false for the stuff you actually want (ie: the stuff you don't want to prune out).

Here's an example:

find . -name .snapshot -prune -o -name '*.foo' -print

This will find the "*.foo" files that aren't under ".snapshot" directories. In this example, -name .snapshot makes up the [conditions to prune], and -name '*.foo' -print is [your usual conditions] and [actions to perform].

Important notes:

  1. If all you want to do is print the results you might be used to leaving out the -print action. You generally don't want to do that when using -prune.

    The default behavior of find is to "and" the entire expression with the -print action if there are no actions other than -prune (ironically) at the end. That means that writing this:

     find . -name .snapshot -prune -o -name '*.foo'              # DON'T DO THIS
    

    is equivalent to writing this:

     find . \( -name .snapshot -prune -o -name '*.foo' \) -print # DON'T DO THIS
    

    which means that it'll also print out the name of the directory you're pruning, which usually isn't what you want. Instead it's better to explicitly specify the -print action if that's what you want:

     find . -name .snapshot -prune -o -name '*.foo' -print       # DO THIS
    
  2. If your "usual condition" happens to match files that also match your prune condition, those files will not be included in the output. The way to fix this is to add a -type d predicate to your prune condition.

    For example, suppose we wanted to prune out any directory that started with .git (this is admittedly somewhat contrived -- normally you only need to remove the thing named exactly .git), but other than that wanted to see all files, including files like .gitignore. You might try this:

    find . -name '.git*' -prune -o -type f -print               # DON'T DO THIS
    

    This would not include .gitignore in the output. Here's the fixed version:

    find . -name '.git*' -type d -prune -o -type f -print       # DO THIS
    

Extra tip: if you're using the GNU version of find, the texinfo page for find has a more detailed explanation than its manpage (as is true for most GNU utilities).

合久必婚 2024-08-12 13:49:39

通常,我们在 Linux 中做事的本机方式以及我们的思维方式是从左到右。

您可以先写下您要查找的内容:

find / -name "*.php"

然后,您按 ENTER 键并意识到您从您不希望的目录中获取了太多文件。

因此,您认为“让我们排除 /media 以避免搜索已安装的驱动器。”

您现在应该将以下内容附加到上一个命令中:

-print -o -path '/media' -prune

最后的命令是:

find / -name "*.php" -print -o -path '/media' -prune
|<--      Include      -->|<--      Exclude      -->|

我认为这种结构更容易并且与正确的方法相关。

Normally, the native way we do things in Linux, and the way we think, is from left to right.

You would go and write what you are looking for first:

find / -name "*.php"

Then, you hit ENTER and realize you are getting too many files from directories you wish not to.

So, you think "let's exclude /media to avoid searching mounted drives."

You should now just append the following to the previous command:

-print -o -path '/media' -prune

and the final command is:

find / -name "*.php" -print -o -path '/media' -prune
|<--      Include      -->|<--      Exclude      -->|

I think this structure is much easier and correlates to the right approach.

缱倦旧时光 2024-08-12 13:49:39

请注意,正如某些人所说, -prune 不会阻止下降到任何目录。它可以防止下降到与其所应用的测试相匹配的目录。也许一些示例会有所帮助(请参阅底部的正则表达式示例)。抱歉,这篇文章太长了。

$ find . -printf "%y %p\n"    # print the file type the first time FYI
d .
f ./test
d ./dir1
d ./dir1/test
f ./dir1/test/file
f ./dir1/test/test
d ./dir1/scripts
f ./dir1/scripts/myscript.pl
f ./dir1/scripts/myscript.sh
f ./dir1/scripts/myscript.py
d ./dir2
d ./dir2/test
f ./dir2/test/file
f ./dir2/test/myscript.pl
f ./dir2/test/myscript.sh

$ find . -name test
./test
./dir1/test
./dir1/test/test
./dir2/test

$ find . -prune
.

$ find . -name test -prune
./test
./dir1/test
./dir2/test

$ find . -name test -prune -o -print
.
./dir1
./dir1/scripts
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.sh
./dir1/scripts/myscript.py
./dir2

$ find . -regex ".*/my.*p.$"
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.py
./dir2/test/myscript.pl

$ find . -name test -prune -regex ".*/my.*p.$"
(no results)

$ find . -name test -prune -o -regex ".*/my.*p.$"
./test
./dir1/test
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.py
./dir2/test

$ find . -regex ".*/my.*p.$" -a -not -regex ".*test.*"
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.py

$ find . -not -regex ".*test.*"                   .
./dir1
./dir1/scripts
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.sh
./dir1/scripts/myscript.py
./dir2

Beware that -prune does not prevent descending into any directory as some have said. It prevents descending into directories that match the test it's applied to. Perhaps some examples will help (see the bottom for a regex example). Sorry for this being so lengthy.

$ find . -printf "%y %p\n"    # print the file type the first time FYI
d .
f ./test
d ./dir1
d ./dir1/test
f ./dir1/test/file
f ./dir1/test/test
d ./dir1/scripts
f ./dir1/scripts/myscript.pl
f ./dir1/scripts/myscript.sh
f ./dir1/scripts/myscript.py
d ./dir2
d ./dir2/test
f ./dir2/test/file
f ./dir2/test/myscript.pl
f ./dir2/test/myscript.sh

$ find . -name test
./test
./dir1/test
./dir1/test/test
./dir2/test

$ find . -prune
.

$ find . -name test -prune
./test
./dir1/test
./dir2/test

$ find . -name test -prune -o -print
.
./dir1
./dir1/scripts
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.sh
./dir1/scripts/myscript.py
./dir2

$ find . -regex ".*/my.*p.$"
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.py
./dir2/test/myscript.pl

$ find . -name test -prune -regex ".*/my.*p.$"
(no results)

$ find . -name test -prune -o -regex ".*/my.*p.$"
./test
./dir1/test
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.py
./dir2/test

$ find . -regex ".*/my.*p.$" -a -not -regex ".*test.*"
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.py

$ find . -not -regex ".*test.*"                   .
./dir1
./dir1/scripts
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.sh
./dir1/scripts/myscript.py
./dir2
溇涏 2024-08-12 13:49:39

添加到其他答案中给出的建议(我没有代表来创建回复)...

-prune 与其他表达式结合使用时,行为上存在细微的差异,具体取决于使用的其他表达式。

@Laurence Gonsalves 的示例将找到不在“.snapshot”目录下的“*.foo”文件:-

find . -name .snapshot -prune -o -name '*.foo' -print

但是,这个略有不同的简写方式可能会无意中列出 .snapshot 目录(以及任何嵌套的 .snapshot 目录):-

find . -name .snapshot -prune -o -name '*.foo'

根据 posix manpage,原因是:

如果给定表达式不包含任何原色 -exec,
-ls、-ok 或 -print,给定的表达式有效地替换为:

(给定表达式)-打印

也就是说,第二个示例相当于输入以下内容,从而修改术语的分组:-

find . \( -name .snapshot -prune -o -name '*.foo' \) -print

这至少已被在 Solaris 5.10 上看到。我已经使用各种风格的 *nix 大约 10 年了,直到最近我才开始寻找发生这种情况的原因。

Adding to the advice given in other answers (I have no rep to create replies)...

When combining -prune with other expressions, there is a subtle difference in behavior depending on which other expressions are used.

@Laurence Gonsalves' example will find the "*.foo" files that aren't under ".snapshot" directories:-

find . -name .snapshot -prune -o -name '*.foo' -print

However, this slightly different short-hand will, perhaps inadvertently, also list the .snapshot directory (and any nested .snapshot directories):-

find . -name .snapshot -prune -o -name '*.foo'

According to the posix manpage, the reason is:

If the given expression does not contain any of the primaries -exec,
-ls, -ok, or -print, the given expression is effectively replaced by:

( given_expression ) -print

That is, the second example is the equivalent of entering the following, thereby modifying the grouping of terms:-

find . \( -name .snapshot -prune -o -name '*.foo' \) -print

This has at least been seen on Solaris 5.10. Having used various flavors of *nix for approx 10 years, I've only recently searched for a reason why this occurs.

狼性发作 2024-08-12 13:49:39

我不是这方面的专家(这个页面与 http://mywiki.wooledge.org/UsingFind< 非常有帮助/a>)

刚刚注意到 -path 是一个完全匹配 find 之后的字符串/路径的路径(. 在这些示例中),其中 -name 匹配所有基本名称。

find . -path ./.git  -prune -o -name file  -print

阻止当前目录中的 .git 目录,因为您在 中找到的内容。

find . -name .git  -prune -o -name file  -print

递归地阻止所有 .git 子目录。

请注意 ./ 非常重要! -path 必须匹配锚定到 的路径。 或者 find 后面的任何内容,如果您在没有它的情况下获得匹配项(从或“-o”)可能没有被修剪!
我天真地没有意识到这一点,当你不想修剪具有相同基本名称的所有子目录时,它让我使用 -path ,这很棒:D

I am no expert at this (and this page was very helpful along with http://mywiki.wooledge.org/UsingFind)

Just noticed -path is for a path that fully matches the string/path that comes just after find (. in theses examples) where as -name matches all basenames.

find . -path ./.git  -prune -o -name file  -print

blocks the .git directory in your current directory ( as your finding in . )

find . -name .git  -prune -o -name file  -print

blocks all .git subdirectories recursively.

Note the ./ is extremely important!! -path must match a path anchored to . or whatever comes just after find if you get matches with out it (from the other side of the or '-o') there probably not being pruned!
I was naively unaware of this and it put me of using -path when it is great when you don't want to prune all subdirectory with the same basename :D

提笔落墨 2024-08-12 13:49:39

find 构建文件列表。它将您提供的谓词应用于每个谓词并返回通过的谓词。

-prune 意味着从结果中排除的想法对我来说真的很困惑。您可以排除文件而不进行修剪:

find -name 'bad_guy' -o -name 'good_guy' -print  // good_guy

-prune 所做的只是改变搜索的行为。如果当前匹配是一个目录,则会显示“嘿查找,您刚刚匹配的文件,不要进入其中”。它只是从要搜索的文件列表中删除该树(而不是文件本身)。

它应该命名为-dont-descend

find builds a list of files. It applies the predicate you supplied to each one and returns those that pass.

This idea that -prune means exclude from results was really confusing for me. You can exclude a file without prune:

find -name 'bad_guy' -o -name 'good_guy' -print  // good_guy

All -prune does is alter the behavior of the search. If the current match is a directory, it says "hey find, that file you just matched, dont descend into it". It just removes that tree (but not the file itself) from the list of files to search.

It should be named -dont-descend.

山川志 2024-08-12 13:49:39

显示所有内容,包括 dir 本身,但不显示其冗长乏味的内容:

find . -print -name dir -prune

Show everything including dir itself but not its long boring contents:

find . -print -name dir -prune
笑脸一如从前 2024-08-12 13:49:39

Prune 是一个“不在该文件中递归”开关(操作)。

从手册页

如果未给出-深度,则为 true;
如果该文件是目录,则不要进入该目录。
如果给定-深度,则为 false;没有效果。

基本上它不会下降到任何子目录。

拿这个例子:

您有以下目录:

% find home
home
home/test1
home/test1/test1
home/test2
home/test2/test2

find home -name test2 将打印名为 test2 的父目录和子目录:

% find home -name test2
home/test2
home/test2/test2

现在,与 -prune...

find home -name test2 -prune 将仅打印 /home/test2;它不会下降到 /home/test2 来查找 /home/test2/test2

% find home -name test2 -prune
home/test2

Prune is a "do not recurse at this file" switch (action).

From the man page

If -depth is not given, true;
if the file is a directory, do not descend into it.
If -depth is given, false; no effect.

Basically it will not descend into any sub directories.

Take this example:

You have the following directories:

% find home
home
home/test1
home/test1/test1
home/test2
home/test2/test2

find home -name test2 will print both the parent and the child directories named test2:

% find home -name test2
home/test2
home/test2/test2

Now, with -prune...

find home -name test2 -prune will print only /home/test2; it will not descend into /home/test2 to find /home/test2/test2:

% find home -name test2 -prune
home/test2
乖乖哒 2024-08-12 13:49:39

如果您阅读了这里所有好的答案,我现在的理解是以下所有结果都返回相同的结果:

find . -path ./dir1\*  -prune -o -print

find . -path ./dir1  -prune -o -print

find . -path ./dir1\*  -o -print
#look no prune at all!

但是最后一个将花费更长的时间,因为它仍然搜索 dir1 中的所有内容。我想真正的问题是如何在不实际搜索的情况下-或剔除不需要的结果。

所以我猜修剪意味着不体面地过去的比赛,但将其标记为完成...

http://www.gnu.org/software/findutils/manual/html_mono/find.html
“然而,这并不是由于‘-prune’动作的影响(它只会阻止进一步下降,并不能确保我们忽略该项目)。相反,这种影响是由于使用‘-o’造成的。由于“或”条件的左侧对于 ./src/emacs 已成功,因此根本没有必要针对该特定文件评估右侧('-print')。”

If you read all the good answers here my understanding now is that the following all return the same results:

find . -path ./dir1\*  -prune -o -print

find . -path ./dir1  -prune -o -print

find . -path ./dir1\*  -o -print
#look no prune at all!

But the last one will take a lot longer as it still searches out everything in dir1. I guess the real question is how to -or out unwanted results without actually searching them.

So I guess prune means don't decent past matches but mark it as done...

http://www.gnu.org/software/findutils/manual/html_mono/find.html
"This however is not due to the effect of the ‘-prune’ action (which only prevents further descent, it doesn't make sure we ignore that item). Instead, this effect is due to the use of ‘-o’. Since the left hand side of the “or” condition has succeeded for ./src/emacs, it is not necessary to evaluate the right-hand-side (‘-print’) at all for this particular file."

痴意少年 2024-08-12 13:49:39

答案有很多;其中一些有点过于理论化。我会留下为什么我需要修剪一次,所以也许需要优先/示例类型的解释对某人有用:)

问题

我有一个包含大约20个节点目录的文件夹,每个都有其预期的 node_modules 目录。

进入任何项目后,您都会看到每个 ../node_modules/module。但你知道它是怎么回事。几乎每个模块都有依赖项,因此您所看到的更像是 projectN/node_modules/moduleX/node_modules/moduleZ...

我不想被包含依赖项的依赖项的列表淹没...

知道 -d n / -深度 n,这对我没有帮助,因为我想要的每个项目的 main/first node_modules 目录位于不同的位置深度,如下所示:

Projects/MysuperProjectName/project/node_modules/...
Projects/Whatshisname/version3/project/node_modules/...
Projects/project/node_modules/...
Projects/MysuperProjectName/testProject/november2015Copy/project/node_modules/...
[...]

如何获取第一个以第一个 node_modules 结尾的路径列表,并移动到下一个项目以获得相同的结果?

输入 -prune

当您添加 -prune 时,您仍然会进行标准的递归搜索。每条“路径”都会被分析,每一个发现都会被吐出,并且 find 像一个好人一样继续挖掘。但这是为了挖掘更多我不想要的node_modules

因此,不同之处在于,在任何这些不同的路径中,-prunefind 在找到您的项目后停止进一步沿着该特定途径挖掘。就我而言,是 node_modules 文件夹。

There are quite a few answers; some of them are a bit too much theory-heavy. I'll leave why I needed prune once so maybe the need-first/example kind of explanation is useful to someone :)

Problem

I had a folder with about 20 node directories, each having its node_modules directory as expected.

Once you get into any project, you see each ../node_modules/module. But you know how it is. Almost every module has dependencies, so what you are looking at is more like projectN/node_modules/moduleX/node_modules/moduleZ...

I didn't want to drown with a list with the dependency of the dependency of...

Knowing -d n / -depth n, it wouldn't have helped me, as the main/first node_modules directory I wanted of each project was at a different depth, like this:

Projects/MysuperProjectName/project/node_modules/...
Projects/Whatshisname/version3/project/node_modules/...
Projects/project/node_modules/...
Projects/MysuperProjectName/testProject/november2015Copy/project/node_modules/...
[...]

How can I get the first a list of paths ending at the first node_modules and move to the next project to get the same?

Enter -prune

When you add -prune, you'll still have a standard recursive search. Each "path" is analyzed, and every find gets spit out and find keeps digging down like a good chap. But it's the digging down for more node_modules what I didn't want.

So, the difference is that in any of those different paths, -prune will find to stop digging further down that particular avenue when it has found your item. In my case, the node_modules folder.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文