我需要从命令中排除一堆路径find
。例如:
find "$(pwd)" -not \( \
-path "*/.git"\
-o -path "*/.git/*"\
-o -path "*/.vscode"\
-o -path "*/.vscode/*"\
-o -path "*/node_modules"\
-o -path "*/node_modules/*"\
-o -path "*/Image"\
-o -path "*/Image/*"\
-o -path "*/Rendered"\
-o -path "*/Rendered/*"\
-o -path "*/iNotebook"\
-o -path "*/iNotebook/*"\
-o -path "*/GeneratedTest"\
-o -path "*/GeneratedTest/*"\
-o -path "*/GeneratedOutput"\
-o -path "*/GeneratedOutput/*"\
-o -path "*/*_files" \) -type d
但是,我想从文本文件中读取这些路径,而不是在命令行上列出所有路径。我怎样才能做到这一点?
答案1
构造一个稍后在调用中使用的数组find
。以下脚本从其标准输入读取换行符分隔的路径模式并调用find
:
#!/bin/sh
set --
while IFS= read -r path; do
set -- "$@" -o -path "$path"
done
shift # remove initial "-o" from $@
find . -type d ! '(' "$@" ')'
你会运行这个
./script.sh <paths.txt
哪里paths.txt
可能看起来像
*/.git
*/.git/*
*/.vscode
*/.vscode/*
*/node_modules
*/node_modules/*
*/Image
*/Image/*
*/Rendered
*/Rendered/*
*/iNotebook
*/iNotebook/*
*/GeneratedTest
*/GeneratedTest/*
*/GeneratedOutput
*/GeneratedOutput/*
*/*_files
或者,因为您的路径模式基本上都是目录名称:
#!/bin/sh
set --
while IFS= read -r dirname; do
set -- "$@" -o '(' -name "$dirname" -prune ')'
done
shift # remove initial "-o" from $@
find . -type d ! '(' "$@" ')'
模式文件包含
.git
.vscode
node_modules
Image
Rendered
iNotebook
GeneratedTest
GeneratedOutput
*_files
代码的这种变体find
甚至会停止下降到与文件中的模式匹配的目录,而第一个脚本(以及您的代码)将-path
针对排除的目录中的所有内容测试模式,无论您是否不是对这些路径以下的任何内容感兴趣。
答案2
您可以使用grep
andfind
来-exec
根据路径列表(作为正则表达式或固定字符串)过滤文件。调整您的示例,创建一个名为paths
包含的文件
/.git$
/.git/
/.vscode$
/.vscode/
/node_modules$
/node_modules/
/Image$
/Image/
/Rendered$
/Rendered/
/iNotebook$
/iNotebook/
/GeneratedTest$
/GeneratedTest/
/GeneratedOutput$
/GeneratedOutput/
/.*_files$
然后运行
find /your/search/path -type d ! -exec sh -c "echo {} | grep -q -f paths" \; -print
这会查找 下的目录/your/search/path
,并且对于它找到的每个目录,用于确定它是否与;grep
中的模式匹配。paths
如果没有,则打印它。这是为了作为扩展的基础;如果您只关心与文件中的模式不匹配的目录路径,和没有路径覆盖多行,您可以使用单个grep
调用对输出进行后处理:
find /your/search/path -type d | grep -v -f paths
如果您真的对某些路径根本不感兴趣(IE您的模式始终匹配目录名称,然后匹配该目录下的所有内容),您可以通过修剪使事情变得更简单:
find /your/search/path -type d \( -exec sh -c "echo {} | grep -q -f paths" \; -prune -o -print \)
路径中包含以下内容:
/.git$
/.vscode$
/node_modules$
/Image$
/Rendered$
/iNotebook$
/GeneratedTest$
/GeneratedOutput$
/.*_files$
答案3
可以做的是使用构建命令awk
并将其find
作为“包装器”脚本或 shell 函数中的变量传递给
p=$( awk '{printf "-not -path %s ",$0}' "$1" )
find "$PWD" $p -type d
并将其称为./find_wrapper.sh paths.txt
,其中path.txt
是引用路径的列表。
'*/.git'
'*/.git/*'
'*/.vscode'
'*/.vscode/*'
'*/node_modules'
'*/node_modules/*'
'*/Image'
...
为什么这样做?构建一整行的原因awk
是因为没有理由在脚本中这样做 -\
行延续是为了使命令看起来更有组织性,但从功能上来说它没有任何优势。$p
没有被引用,因为我们实际上想要在这里进行分词。否则find
将其视为一个巨大的字符串,而不是单独的标志和参数。至于单引号,那就是以避免全局双引号中的效果。
或者作为管道
awk '{printf "-not -path %s ",$0}' "$1" | xargs -L 1 find "$PWD" -type d