对 find 命令的输出进行排序,读回以删除文件

对 find 命令的输出进行排序,读回以删除文件

以下bash脚本搜索所有目录并列出每个目录中有多少文件。

下面是我自己的 R 安装的示例输出测试 - 正是我所需要的。

find . -mindepth 6  -type d -print0 | while IFS= read -r -d '' i ; do echo -n $i": " ; ls -p "$i" | grep -v / | wc -l ; done

我的问题是,如何将此输出“files.txt”(例如)读取到另一个语句中,例如:

xargs rm -f files.txt    # ("<" is missing)

读取包含所有目录的files.txt内容,并删除其中包含多个文件的目录中的所有文件(仅文件,而不是文件夹,目录结构不得更改)?

在下面的输出中,每个目录中的所有文件都将被删除,不包括 -

./R/R-3.6.1/src/library/tcltk/R/windows: 1  
./R/R-3.6.1/src/library/compiler/man: 1   
./R/R-3.6.1/src/library/compiler/R: 1

示例输出:

./R/R-3.6.1/src/library/tools/man: 64   
./R/R-3.6.1/src/library/tools/tests: 3   
./R/R-3.6.1/src/library/tools/src: 16  
./R/R-3.6.1/src/library/tools/po: 23  
./R/R-3.6.1/src/library/tools/R: 49    
./R/R-3.6.1/src/library/tcltk: 4   
./R/R-3.6.1/src/library/tcltk/man: 14  
./R/R-3.6.1/src/library/tcltk/exec: 12  
./R/R-3.6.1/src/library/tcltk/src: 7   
./R/R-3.6.1/src/library/tcltk/po: 21  
./R/R-3.6.1/src/library/tcltk/R: 6   
./R/R-3.6.1/src/library/tcltk/R/unix: 2  
./R/R-3.6.1/src/library/tcltk/R/windows: 1  
./R/R-3.6.1/src/library/tcltk/demo: 5  
./R/R-3.6.1/src/library/compiler: 4  
./R/R-3.6.1/src/library/compiler/man: 1  
./R/R-3.6.1/src/library/compiler/noweb: 2  
./R/R-3.6.1/src/library/compiler/tests: 10  
./R/R-3.6.1/src/library/compiler/po: 10  
./R/R-3.6.1/src/library/compiler/R: 1   
./R/R-3.6.1/src/library/graphics: 4

谢谢。

答案1

如果您想读入文件,rm那么每一行都需要采用有意义的形式,告诉您rm删除列出的目录中的所有文件,即

rm ./path/to/delete/*

所以....

sed -E "s|:\s[0-9]+$|/*|" files.txt

指示将文件中sed每次出现的序列:空白、\s一个或多个数字[0-9]+和行结尾替换为.$/*

如果你按原样输入它,rm那么它会抛出一个错误,因为你还要求它删除目录,所以,如果消息让你出错,请重定向 stderr

rm $(sed -E "s|:\s[0-9]+$|/*|" files.txt) 2>/dev/null

如果目录名称中有空格,这将失败,在这种情况下,仍然坚持将文件提供给rm,您可以IFS稍后更改并重置它

OFS=$IFS; IFS=$'\n'; rm $(sed -E "s|:\s[0-9]+$|/*|" files.txt) 2>/dev/null; IFS=$OFS

答案2

像这样的东西吗?

find . -type f -mindepth 6 \
  | sed -r 's:/[^/]+$::' \
  | sort \
  | uniq -c \
  | awk '$1 > 1 {print $2}' \
  | xargs -i% find % -type f -delete

分解

find . -type f -mindepth 6获取文件列表

sed -r 's:/[^/]+$::'删除文件名,只保留目录

sort下一个命令需要正确工作

uniq -c计算连续的唯一行

awk '$1 > 1 {print $2}'过滤掉只找到 1 个项目的地方,剩下的有 2 个或更多文件

xargs -i% find % -type f -delete在每个结果目录中搜索文件并将其全部删除

通过一些后空翻和临时文件,我们可能可以避免执行xargs find,而是获取要从输入中删除的内容列表。

答案3

由于您已经有了一种方法来检测哪些目录包含多个文件,并且结果存储在一个文件中(您称之为files.txt),因此您可以使用 shell 脚本来完成该任务:

#!/bin/bash

IFS=":"
while read path count
do
    if (( count > 1 ))
    then
        echo "Remove all files in $path (count = $count)"
        rm "$path/"*
    fi
done < files.txt

相关内容