首页 文章

如何在find中排除目录 . 命令

提问于
浏览
988

我正在尝试为所有JavaScript文件运行 find 命令,但如何排除特定目录?

这是我们正在使用的 find 代码 .

for file in $(find . -name '*.js')
do 
  java -jar config/yuicompressor-2.4.2.jar --type js $file -o $file
done

30 回答

  • 166

    我使用 findxgettext 提供了一个文件列表,并希望省略特定目录及其内容 . 我尝试了 -path-prune 结合的许多排列,但无法完全排除我想要的目录 .

    虽然我能够忽略我想要忽略的目录的内容,但是 find 然后将目录本身作为结果之一返回,这导致 xgettext 因此而崩溃(不接受目录;仅接受文件) .

    我的解决方案是简单地使用 grep -v 跳过结果中我不想要的目录:

    find /project/directory -iname '*.php' -or -iname '*.phtml' | grep -iv '/some/directory' | xargs xgettext
    

    无论是否有 find 的论证都能100%发挥作用,我无法肯定地说 . 在经历了一些头痛之后,使用 grep 是一个快速而简单的解决方案 .

  • 2

    以前的答案都没有在Ubuntu上有用 . 试试这个:

    find . ! -path "*/test/*" -type f -name "*.js" ! -name "*-min-*" ! -name "*console*"
    

    我发现了这个here

  • 1

    这适合我在Mac上:

    find . -name *.php -or -path "./vendor" -prune -or -path "./app/cache" -prune
    

    对于以 php 为后缀的搜索名称,它将排除 vendorapp/cache dir .

  • 11

    要排除多个目录:

    find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" \)
    

    要添加目录,请添加 -o -path "./dirname/*"

    find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" -o -path "./dir3/*"\)
    

    但是,如果要排除许多目录,也许你应该使用regular expression .

  • 18

    对于我需要的工作,这样工作,从root开始在所有服务器中找到 landscape.jpg 并排除 /var 目录中的搜索:

    find / -maxdepth 1 -type d | grep -v /var | xargs -I '{}' find '{}' -name landscape.jpg

    find / -maxdepth 1 -type d 列出 / 中的所有 d irectories

    grep -v /var 从列表中排除`/ var'

    xargs -I '{}' find '{}' -name landscape.jpg 对列表中的每个目录/结果执行任何命令,如 find

  • 766

    这里有很多答案;我不愿意添加另一个,但我认为这些信息很有用 .

    TLDR: 了解您的根目录并使用“ -prune ”选项从那里定制搜索 .

    Background: 我有一个 rsnapshotrsync )备份位置, /mnt/Backups/ ,在搜索系统( / )文件时会引起麻烦,因为这些备份包含~4.5TB(terra)的文件!

    我还有 /mnt/Vancouver ,我的主要工作文件夹,TB文件,备份[ /mnt/Backups//mnt/Vancouver/ 物理(冗余)安装在不同的驱动器上] .


    在这里的两个最佳答案(How to exclude a directory in find . command)中,我发现使用接受的答案搜索系统文件的速度要快得多 much .

    这个

    find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
    

    在~3-4秒内找到该文件;这个

    find / -name "*libname-server-2.a*" -not -path "/mnt/*"
    

    出现(?)来递归所有被排除的目录(所有已安装卷的深层嵌套 rsync 快照),因此它需要 forever . 我无休止地陷入困境 . 例如,如果我尝试搜索"time"( time find ... ),我会看到大量输出 - 表明 find 正在深入遍历"excluded"目录:

    ...
    find: ‘/mnt/Backups/rsnapshot_backups/monthly.0/snapshot_root/var/lib/udisks2’: Permission denied
    ...
    

    在排除目录( /mnt/ )或嵌套路径(`/ mnt / Backups')后附加正斜杠会导致搜索 again* 永远占用:

    Slow:

    find / -path /mnt/ -prune -o -name "*libname-server-2.a*" -print
    find / -path /mnt/Vancouver -prune -o -name "*libname-server-2.a*" -print
    

    "SOLUTION"

    这是最好的解决方案(所有这些都在几秒钟内执行) . 同样,我的目录结构是

    • / :root

    • /mnt/Backups/ :多TB备份

    • /mnt/Vancouver/ :多TB工作目录(在单独的驱动器上备份到 /mnt/Backups ),我经常要搜索

    • /home/* :其他挂载点/工作"drives"(例如 /home/victoria = ~

    System files (/):

    要快速查找系统文件,请排除 /mntnot /mnt//mnt/Backups ,...):

    $ find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
    /usr/lib/libname-server-2.a
    

    在~3-4秒内找到该文件 .

    Non-system files:

    例如 . 快速找到我的两个工作"drives", /mnt/Vancouver/ 和/或 /home/victoria/ 中的一个文件 .

    $ find /mnt/Vancouver/ -name "*04t8ugijrlkj.jpg"
    /mnt/Vancouver/temp/04t8ugijrlkj.jpg
    
    $ find /home/victoria -iname "*Untitled Document 1"
    /home/victoria/backups/shortcuts.bak.2016.11.02/Untitled Document 1
    /home/victoria/Untitled Document 1
    

    Backups:

    例如 . 在我的每小时/每日/每周/每月备份之一中查找已删除的文件 .

    $ find /mnt/Backups/rsnapshot_backups/daily.0 -name "*04t8ugijrlkj.jpg"
    /mnt/Backups/rsnapshot_backups/daily.0/snapshot_root/mnt/Vancouver/temp/04t8ugijrlkj.jpg
    

    Aside: 在命令末尾添加-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
    $
    
  • 3

    for 循环更好地使用 exec 动作:

    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 手册页的示例部分

  • 2

    如果搜索目录有模式(在我的情况下大多数情况下);你可以像下面这样简单地做:

    find ./n* -name "*.tcl"
    

    在上面的例子中;它搜索以“n”开头的所有子目录 .

  • 8

    我更喜欢 -not 符号......它更具可读性:

    find . -name '*.js' -and -not -path directory
    
  • 14

    这是我用来排除某些路径的格式:

    $ find ./ -type f -name "pattern" ! -path "excluded path" ! -path "excluded path"
    

    我用它来查找不在“ . *”路径中的所有文件:

    $ find ./ -type f -name "*" ! -path "./.*" ! -path "./*/.*"
    
  • 7
    find . -name '*.js' -\! -name 'glob-for-excluded-dir' -prune
    
  • 1
    find -name '*.js' -not -path './node_modules/*' -not -path './vendor/*'
    

    似乎工作相同

    find -name '*.js' -not \( -path './node_modules/*' -o -path './vendor/*' \)
    

    并且更容易记住IMO .

  • 2

    一种选择是排除所有包含grep目录名的结果 . 例如:

    find . -name '*.js' | grep -v excludeddir
    
  • 0

    -prune 肯定有效并且是最佳答案,因为它可以防止降级到要排除的目录 . -not -path 仍在搜索排除的目录,它只是没有't print the result, which could be an issue if the excluded dir is mounted network volume or you don't权限 .

    棘手的部分是 find 非常特别关于参数的顺序,所以如果你没有得到它们恰到好处,那么你的命令可能不起作用 . 参数的顺序通常是这样的:

    find {path} {options} {action}
    

    {path} :首先放入所有与路径相关的参数,如 . -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
    
  • 1610

    我发现C源文件中的函数名不包括* .o和排除* .swp和exclude(不是常规文件),并使用此命令排除dir输出:

    find .  \( ! -path "./output/*" \) -a \( -type f \) -a \( ! -name '*.o' \) -a \( ! -name '*.swp' \) | xargs grep -n soc_attach
    
  • 6

    对于FreeBSD用户:

    find . -name '*.js' -not -path '*exclude/this/dir*'
    
  • 0

    有很多好的答案,我花了一些时间来理解命令的每个元素是什么以及它背后的逻辑 .

    find . -path ./misc -prune -o -name '*.txt' -print
    

    find将开始在当前目录中查找文件和目录,因此 find . .

    -o 选项代表逻辑OR,并将命令的两个部分分开:

    [ -path ./misc -prune ] OR [ -name '*.txt' -print ]
    

    not ./misc目录中的任何目录或文件都不会通过第一个测试 -path ./misc . 但他们将针对第二个表达进行测试 . 如果它们的名称对应于模式 *.txt ,则会打印它们,因为 -print 选项 .

    当find到达./misc目录时,此目录仅满足第一个表达式 . 因此 -prune 选项将应用于它 . 它告诉find命令 not 探索该目录 . 因此,./misc中的任何文件或目录都不会被find探索,也不会针对表达式的第二部分进行测试,也不会被打印 .

  • 21

    对于工作解决方案(在Ubuntu 12.04(精确穿山甲)上测试)...

    find ! -path "dir1" -iname "*.mp3"
    

    将在dir1子文件夹中搜索当前文件夹和子文件夹中的MP3文件 .

    使用:

    find ! -path "dir1" ! -path "dir2" -iname "*.mp3"
    

    ...排除dir1和dir2

  • 1

    这是唯一适合我的人 .

    find / -name NameOfFile ! -path '*/Directory/*'
    

    搜索“NameOfFile”,不包括“目录” . 强调星星* .

  • 1

    how-to-use-prune-option-of-find-in-shLaurence 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
    
  • 1

    我试过上面的命令,但没有一个使用“-prune”的人对我有用 . 最后我用下面的命令尝试了这个:

    find . \( -name "*" \) -prune -a ! -name "directory"
    
  • 47

    这是因为 find TESTS pattern “* foo *”的文件:

    find ! -path "dir1" ! -path "dir2" -name "*foo*"
    

    但如果你不使用 patternfindTEST 文件),它确实 NOT 工作 . 所以 find 没有使用它以前评估的“真" & "假”bools . 上述表示法不工作用例的示例:

    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
    

    问候

  • 39

    使用剪枝开关,例如,如果要排除 misc 目录,只需在查找命令中添加 -path ./misc -prune -o

    find . -path ./misc -prune -o -name '*.txt' -print
    

    这是一个包含多个目录的示例:

    find . -type d \( -path dir1 -o -path dir2 -o -path dir3 \) -prune -o -print
    

    这里我们排除了dir1,dir2和dir3,因为在 find 表达式中它是一个动作,它作用于标准 -path dir1 -o -path dir2 -o -path dir3 (如果dir1或dir2或dir3),与 type -d 进行AND运算 . 进一步的行动是 -o print ,只是打印 .

  • 3

    如果 -prune 不适合您,则会:

    find -name "*.js" -not -path "./directory/*"
    
  • 373

    您可以使用prune选项来实现此目的 . 例如:

    find ./ -path ./beta/* -prune -o -iname example.com -print
    

    或者反向grep“grep -v”选项:

    find -iname example.com | grep -v beta
    

    您可以在Linux find command exclude directories from searching中找到详细的说明和示例 .

  • 7

    使用-prune选项 . 所以,像:

    find . -type d -name proc -prune -o -name '*.js'
    

    '-type d -name proc -prune'仅查找名为proc的目录以进行排除 .
    '-o'是'OR'运算符 .

  • 7

    -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 \)
    
  • 2

    对于那些不能使用 -path-not 的旧版UNIX的用户

    测试了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
    
  • 1

    我发现以下比其他提议的解决方案更容易推理:

    find build -not \( -path build/external -prune \) -name \*.js
    

    这来自一个实际的用例,我需要在wintersmith生成的一些文件上调用yui-compressor,但是遗漏了需要按原样发送的其他文件 .

    里面 \(\) 是一个匹配 exactly build/external 的表达式(例如,如果你做 find ./build 则不匹配 - 在这种情况下你需要将它改为 ./build/external ),并且在成功时将避免遍历下面的任何内容 . 然后将其分组为带有转义括号的单个表达式,并以 -not 为前缀,这将使 find 跳过与该表达式匹配的任何内容 .

    有人可能会问是否添加 -not 不会重新出现 -prune 隐藏的所有其他文件,答案是否定的 . -prune 的工作方式是,一旦到达,该目录下面的文件将被永久忽略 .

    这也很容易扩展,以添加额外的排除 . 例如:

    find build -not \( -path build/external -prune \) -not \( -path build/blog -prune \) -name \*.js
    
  • 0

    这里显然有一些混淆,即跳过目录的首选语法应该是什么 .

    GNU Opinion

    To ignore a directory and the files under it, use -prune
    

    From the GNU find man page

    Reasoning

    -prune 阻止 find 进入目录 . 只需指定 -not -path 仍然会进入跳过的目录,但只要 find 测试每个文件, -not -path 就会为false .

    Issues with -prune

    -prune 做了它的目的,但在使用它时仍然需要注意一些事情 .

    • find 打印已修剪的目录 .

    • TRUE 那's intended behavior, it just doesn' t进入它 . 要避免完全打印目录,请使用逻辑上省略它的语法 .

    • -prune 仅适用于 -print 且无其他操作 .

    • NOT TRUE . -prune 适用于除 -delete 之外的任何操作 . 为什么删除不起作用?要 -delete 工作,find需要以DFS顺序遍历目录,因为 -delete 将首先删除叶子,然后删除叶子的父级等...但是为了指定 -prune 有意义, find 需要命中目录并停止降序,这显然没有 -depth-delete 开启 .

    Performance

    我在这个问题上设置了一个关于三个最高评价答案的简单测试(用 -exec bash -c 'echo $0' {} \; 替换 -print 以显示另一个动作示例) . 结果如下

    ----------------------------------------------
    # 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
    

    Conclusion

    f10bit's syntaxDaniel C. Sobral's syntax平均需要10-25ms才能运行 . GetFree's syntax,不使用 -prune ,耗时865ms . 所以,是的,这是一个相当极端的例子,但如果你关心运行时间并且正在做任何远程密集的事情,你应该使用 -prune .

    注意Daniel C. Sobral's syntax执行了两个 -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
    

相关问题