在 bash 中,有什么快速且不太复杂的方法可以删除目录中 x 行以下的所有文件?
答案1
这是一个 POSIX 解决方案,应该非常容易理解:
find . -type f -exec awk -v x=10 'NR==x{exit 1}' {} \; -exec echo rm -f {} \;
如在斯蒂芬的回答,删除echo
当满意的时候就会删除。
为 Unix/Linux 新手编写的解释:
点.
代表当前目录。 find
在 中递归查找文件和目录.
,并可以对它们执行操作。
-type
是其中find
之一初选;这是一个将对递归找到的每个文件和目录(在 内)执行的测试.
,并且仅在结果为“true”时才评估该行上的其余主项。
在这种特殊情况下,只有当我们正在处理一个常规文件,而不是目录或其他东西(例如块设备。)
主-exec
节点 ( 的find
) 调用外部命令,并且只有在外部命令成功退出(退出状态为“0”)时才继续执行下一个主节点。{}
被命令“考虑”的文件名替换find
。所以第一次-exec
调用相当于下面的shell命令,依次对每个文件执行:
awk -v x=10 'NR==x{exit 1}' ./somefilename
awk 本身就是一门完整的语言,设计用于处理分隔文本文件,例如 CSV。 Awk 条件和命令(包含在单引号之间并以字母 开头NR
)针对文本文件的每一行执行。 (隐式循环。)
要充分学习 Awk,我强烈推荐格莱莫尔教程,但我将解释上述命令中使用的 Awk 功能。
Awk标志-v
允许我们在执行 Awk 命令之前(针对文件的每一行)设置一个 Awk 变量(一次)。在本例中,我们设置x
为10
。
NR
是一个特殊的 Awk 变量,指的是“氮当前的数量右ecord。”换句话说,它是我们在循环中的任何特定传递中查看的行号。
(请注意,它是尽管不寻常,但可能使用不同的“右埃科德Separator" 比默认的换行符,通过设置RS
. 这是使用记录分隔符播放的示例。)
awk 脚本一般包括状况(花括号外)结合行动(在大括号内。)可以有复合条件和复合操作,并且有一个默认条件(true)和一个默认操作(print),但我们不需要理会这些。
这状况这是“这是第 10 行吗?”如果是这种情况,我们将以非零退出状态退出,这在 shell 脚本中意味着“命令终止失败”。
因此该 Awk 命令退出的唯一方法成功地是指在到达第 10 行之前是否到达文件末尾。
因此,如果 awk 脚本成功退出,则意味着您有一个少于十行的文件。
下一个-exec
调用(如果删除echo
)将通过运行以下命令删除每个文件(在评估 的初选中达到如此程度find
):
rm -f ./somefilename
答案2
假设一个find
支持-readable
谓词的实现(如果您find
不支持它,只需将其删除,您只会收到不可读文件的错误消息,或替换为-exec test -r {} \;
):
x=10 find . -type f -readable -exec sh -c '
for file do
lines=$(wc -l < "$file") && [ "$((lines))" -lt "$x" ] && echo rm -f "$file"
done' sh {} +
删除echo
如果高兴。
这并不是特别有效,因为它很重要全部每个文件中的行,而它只需要停在第x
一个文件,并且它为每个文件运行一个wc
(也可能是一个rm
)命令。
使用 GNU awk
,您可以通过以下方式提高效率:
x=10
find . -type f -readable -exec awk -v x="$x" -v ORS='\0' '
FNR == x {nextfile}
ENDFILE {if (FNR < x) print FILENAME}' {} +|
xargs -r0 echo rm -f
(再次,echo
高兴时删除)。
与以下相同perl
:
x=10 find . -type f -readable -exec perl -Tlne '
if ($. == $ENV{x}) {close ARGV}
elsif (eof) {print $ARGV; close ARGV}' {} +
print
如果高兴的话就换成unlink
。
答案3
为了完整起见,除了 AWK 之外,您还可以使用 GNU sed 来实现相同的结果:
find . -type f -exec sed 11q1 '{}' ';' -exec echo rm -f '{}' ';'
这会导致命令行更加简洁。
解释
11 - is the address, i.e. "the eleventh line"
q - is for _q_uit (abort the execution)
1 - is the exit code parameter for q (GNU sed extension)