grep按路径排除文件/目录仅最后规则生效,如何解决?
解决grep过滤排除规则仅最后一条生效的问题
你的问题根源在于两个细节:
- 换行符格式问题:如果
$to_skip是Windows格式(每行结尾带\r),grep -Ff会把\r当成匹配字符串的一部分,导致前面的规则无法匹配正确路径,只有最后一行可能因无多余换行符生效。 - 目录排除逻辑问题:原
$to_skip中的目录路径(如/test/ex1/subfolder)只能精确匹配路径本身,但第一个grep输出的是目录下的文件路径(如/test/ex1/subfolder/fileC),精确匹配无法排除这些子文件。
下面是几种可行的解决方案:
方案1:修复换行符+正则匹配规则
步骤1:修复$to_skip的换行符
将文件转为Unix格式,去除多余的\r:
dos2unix "$to_skip" # 无dos2unix时用sed替代 sed -i 's/\r$//' "$to_skip"
步骤2:调整排除规则为正则格式
编辑$to_skip,将每条规则改为:
- 文件路径:用
^和$做精确匹配 - 目录路径:用
^目录路径/.*$匹配目录下所有文件
示例调整后的内容:
^/test/ex1/fileA$ ^/test/bob/ex1/fileB$ ^/test/ex1/subfolder/.*$ ^/test/jerry/ex2/.*$
步骤3:执行过滤命令
改用扩展正则匹配的grep -Ef:
grep -nriFlI "$string" "/test" | grep -vEf "$to_skip" > "$out"
方案2:用awk灵活处理(无需修改原$to_skip)
用awk自动区分文件和目录,匹配路径前缀实现过滤:
grep -nriFlI "$string" "/test" | awk -v skip_file="$to_skip" ' BEGIN { # 读取排除规则到数组 while ((getline line < skip_file) > 0) { sub(/\r?$/, "", line) # 去除Windows换行符 if (system("[ -d \"" line "\" ]") == 0) { # 目录存储为带/的前缀 dirs[line "/"] = 1 } else { # 文件存储为精确路径 files[line] = 1 } } close(skip_file) } { current_path = $0 # 跳过排除文件 if (current_path in files) next # 跳过排除目录下的所有文件 for (dir in dirs) { if (index(current_path, dir) == 1) { next } } print current_path }' > "$out"
方案3:find+grep一步到位(更高效)
直接用find处理排除规则,再调用grep检索内容,避免管道传递路径的问题:
find /test -type f $(awk '{ sub(/\r?$/, "", $0) if (system("[ -d \"" $0 "\" ]") == 0) { printf "! -path \"%s/*\" ", $0 } else { printf "! -path \"%s\" ", $0 } }' "$to_skip") -exec grep -nqFlI "$string" {} \; -print > "$out"
内容的提问来源于stack exchange,提问作者user9952796
相关产品推荐
相关产品推荐

