【问题标题】:Use find command but exclude files in two directories使用 find 命令但排除两个目录中的文件
【发布时间】:2013-01-03 02:21:32
【问题描述】:

我想查找以_peaks.bed 结尾的文件,但排除tmpscripts 文件夹中的文件。

我的命令是这样的:

 find . -type f \( -name "*_peaks.bed" ! -name "*tmp*" ! -name "*scripts*" \)

但它没有用。 tmpscript 文件夹中的文件仍会显示。

有人对此有想法吗?

【问题讨论】:

    标签: linux shell unix find


    【解决方案1】:

    以下是您可以使用find 指定的方法:

    find . -type f -name "*_peaks.bed" ! -path "./tmp/*" ! -path "./scripts/*"
    

    说明:

    • find . - 从当前工作目录开始查找(默认递归)
    • -type f - 向 find 指定您只需要结果中的文件
    • -name "*_peaks.bed" - 查找名称以 _peaks.bed 结尾的文件
    • ! -path "./tmp/*" - 排除路径以./tmp/ 开头的所有结果
    • ! -path "./scripts/*" - 同时排除路径以./scripts/ 开头的所有结果

    测试解决方案:

    $ mkdir a b c d e
    $ touch a/1 b/2 c/3 d/4 e/5 e/a e/b
    $ find . -type f ! -path "./a/*" ! -path "./b/*"
    
    ./d/4
    ./c/3
    ./e/a
    ./e/b
    ./e/5
    

    您非常接近,-name 选项仅考虑基本名称,而 -path 考虑整个路径 =)

    【讨论】:

    • 干得好。但是,您忘记了 OP 想要的一件事,即查找以 _peaks.bed 结尾的文件。
    • 这在 GNU find 中使用了一些扩展名,但由于问题被标记为 Linux,所以这不是问题。很好的答案。
    • 简短说明:如果您在初始查找提示中使用.,则必须在您排除的每个路径中使用它。路径匹配非常严格,它不做模糊搜索。因此,如果您使用find / -type f -name *.bed" ! -path "./tmp/",它将无法正常工作。你需要有! -path "/tmp" 才能让它快乐。
    • 重要的是要注意 * 很重要。 $ ! -path "./directory/*"
    • 根据手册页:“要忽略整个目录树,请使用 -prune 而不是检查树中的每个文件。”如果您排除的目录运行得很深或有大量文件并且您关心性能,那么请改用-prune 选项。
    【解决方案2】:

    这是您可以做到的一种方法...

    find . -type f -name "*_peaks.bed" | egrep -v "^(./tmp/|./scripts/)"
    

    【讨论】:

    • 这具有使用find 的任何版本的优点,而不仅仅是使用GNU find。但是,这个问题被标记为 Linux,所以这并不重要。
    【解决方案3】:

    使用

    find \( -path "./tmp" -o -path "./scripts" \) -prune -o  -name "*_peaks.bed" -print
    

    find \( -path "./tmp" -o -path "./scripts" \) -prune -false -o  -name "*_peaks.bed"
    

    find \( -path "./tmp" -path "./scripts" \) ! -prune -o  -name "*_peaks.bed"
    

    顺序很重要。它从左到右评估。 始终从路径排除开始。

    说明

    不要使用-not(或!)排除整个目录。使用-prune。 如手册中所述:

    −prune    The primary shall always evaluate as  true;  it
              shall  cause  find  not  to descend the current
              pathname if it is a directory.  If  the  −depth
              primary  is specified, the −prune primary shall
              have no effect.
    

    并在 GNU 查找手册中:

    -path pattern
                  [...]
                  To ignore  a  whole
                  directory  tree,  use  -prune rather than checking
                  every file in the tree.
    

    确实,如果你使用-not -path "./pathname", find 将评估 "./pathname" 下每个节点的表达式。

    find 表达式只是条件评估。

    • \( \) - 分组操作(可以使用-path "./tmp" -prune -o -path "./scripts" -prune -o,但更冗长)。
    • -path "./script" -prune - 如果 -path 返回 true 并且是一个目录,则为该目录返回 true 并进入该目录。
    • -path "./script" ! -prune - 它评估为(-path "./script") AND (! -prune)。它将修剪的“始终正确”恢复为始终错误。它避免打印 "./script" 作为匹配项。
    • -path "./script" -prune -false - 因为-prune 总是返回true,你可以在它后面加上-false 来做与! 相同的事情。
    • -o - 或运算符。如果两个表达式之间没有指定运算符,则默认为 AND 运算符。

    因此,\( -path "./tmp" -o -path "./scripts" \) -prune -o -name "*_peaks.bed" -print 扩展为:

    [ (-path "./tmp" OR -path "./script") AND -prune ] OR ( -name "*_peaks.bed" AND print )
    

    打印在这里很重要,因为没有它会扩展为:

    { [ (-path "./tmp" OR -path "./script" )  AND -prune ]  OR (-name "*_peaks.bed" ) } AND print
    

    -print 由 find 添加 - 这就是为什么大多数时候,您不需要在表达式中添加它。并且由于-prune 返回true,它将打印“./script”和“./tmp”。

    在其他情况下没有必要,因为我们将 -prune 切换为始终返回 false。

    提示:您可以使用find -D opt expr 2>&1 1>/dev/null查看它是如何优化和扩展的,
    find -D search expr 2>&1 1>/dev/null查看检查了哪个路径。

    【讨论】:

    • 如果没有 -name 谓词,这似乎不起作用 - 即当使用 -type f 按类型查找文件时。我收到错误 find: paths must before expression.
    • @HashimAziz 我无法复制。它适用于我身边的find \( -path <path> -o -path <path> \) -prune -false -o -type f。如果我在命令中忘记了-(例如输入type f 而不是-type f,则会收到类似的错误消息。您要运行哪个命令?
    • 是的,原来是我的语法有问题,我不得不在那里添加一个-not。我会删除我的 cmets。
    【解决方案4】:

    对我来说,这个解决方案不适用于带有 find 的命令 exec,真的不知道为什么,所以我的解决方案是

    find . -type f -path "./a/*" -prune -o -path "./b/*" -prune -o -exec gzip -f -v {} \;
    

    解释:和sampson-chen一样,加了

    -prune - 忽略...的处理路径

    -o - 如果不匹配则打印结果,(修剪目录并打印剩余结果)

    18:12 $ mkdir a b c d e
    18:13 $ touch a/1 b/2 c/3 d/4 e/5 e/a e/b
    18:13 $ find . -type f -path "./a/*" -prune -o -path "./b/*" -prune -o -exec gzip -f -v {} \;
    
    gzip: . is a directory -- ignored
    gzip: ./a is a directory -- ignored
    gzip: ./b is a directory -- ignored
    gzip: ./c is a directory -- ignored
    ./c/3:    0.0% -- replaced with ./c/3.gz
    gzip: ./d is a directory -- ignored
    ./d/4:    0.0% -- replaced with ./d/4.gz
    gzip: ./e is a directory -- ignored
    ./e/5:    0.0% -- replaced with ./e/5.gz
    ./e/a:    0.0% -- replaced with ./e/a.gz
    ./e/b:    0.0% -- replaced with ./e/b.gz
    

    【讨论】:

    • 接受的答案无效,但这有效。使用修剪,find . -path ./scripts -prune -name '*_peaks.bed' -type f。不确定如何排除多个目录。即使指定了type,这也会列出顶级排除目录。除非您想使用 prune 来加快查找操作,否则通过 Grep 排除似乎更简单。
    • 我也无法排除多个目录,但上面的 cmets 给了我一个有效的答案。我使用了“-not -path”的多个实例,并且在每个路径表达式中,我都包含了“find”的第一个参数中使用的完整前缀,并以星号结尾(并转义任何点)。
    【解决方案5】:

    你可以试试下面的:

    find ./ ! \( -path ./tmp -prune \) ! \( -path ./scripts -prune \) -type f -name '*_peaks.bed'
    

    【讨论】:

    • 关于这样的老问题(4 年!),您想解释为什么这个新答案更好或不同,而不仅仅是“转储”代码。
    【解决方案6】:

    试试类似的东西

    find . \( -type f -name \*_peaks.bed -print \) -or \( -type d -and \( -name tmp -or -name scripts \) -and -prune \)
    

    如果我弄错了也不要太惊讶。如果目标是 exec(而不是 print),只需将其替换到位。

    【讨论】:

      【解决方案7】:

      通过这些解释,您可以实现您的目标和许多其他目标。随心所欲地加入每个部分。

      型号

      find ./\
       -iname "some_arg" -type f\ # File(s) that you want to find at any hierarchical level.
       ! -iname "some_arg" -type f\ # File(s) NOT to be found on any hirearchic level (exclude).
       ! -path "./file_name"\ # File(s) NOT to be found at this hirearchic level (exclude).
       ! -path "./folder_name/*"\ # Folder(s) NOT to be found on this Hirearchic level (exclude).
       -exec grep -IiFl 'text_content' -- {} \; # Text search in the content of the found file(s) being case insensitive ("-i") and excluding binaries ("-I").
      

      示例

      find ./\
       -iname "*" -type f\
       ! -iname "*pyc" -type f\
       ! -path "./.gitignore"\
       ! -path "./build/*"\
       ! -path "./__pycache__/*"\
       ! -path "./.vscode/*"\
       ! -path "./.git/*"\
       -exec grep -IiFl 'title="Brazil - Country of the Future",' -- {} \;
      

      谢谢! ???

      [参考文献: https://unix.stackexchange.com/q/73938/61742 ]


      额外:

      您可以将上面的命令与您喜欢的编辑器一起使用并分析找到的文件的内容,例如...

      vim -p $(find ./\
       -iname "*" -type f\
       ! -iname "*pyc" -type f\
       ! -path "./.gitignore"\
       ! -path "./build/*"\
       ! -path "./__pycache__/*"\
       ! -path "./.vscode/*"\
       ! -path "./.git/*"\
       -exec grep -IiFl 'title="Brazil - Country of the Future",' -- {} \;)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-05-11
        • 1970-01-01
        • 1970-01-01
        • 2023-04-02
        • 1970-01-01
        • 1970-01-01
        • 2012-11-07
        • 1970-01-01
        相关资源
        最近更新 更多