Wil*_*ard 12
这是一个 POSIX 解决方案,应该很容易理解:
find . -type f -exec awk -v x=10 'NR==x{exit 1}' {} \; -exec echo rm -f {} \;
Run Code Online (Sandbox Code Playgroud)
正如在Stephane 的回答中一样,删除对echo
将要删除的内容感到满意的时候。
点.
代表当前目录。 find
在 中递归查找文件和目录.
,并可以对它们进行处理。
-type
是find
的初选之一;这是一个测试,将对递归找到的每个文件和目录(在 内.
)执行,并且仅当结果为“true”时才评估该行上的其余主要部分。
在这种特殊情况下,我们只有在处理常规文件时才继续,而不是目录或其他东西(例如块设备)。
的-exec
主(共find
)调用外部命令,并且仅进行到下一个主如果成功的外部命令退出(“0”退出状态)。将{}
被替换的文件名被“认为是”被find
命令。所以第一次-exec
调用相当于下面的shell命令,依次对每个文件执行:
awk -v x=10 'NR==x{exit 1}' ./somefilename
Run Code Online (Sandbox Code Playgroud)
Awk 本身就是一门完整的语言,设计用于处理带分隔符的文本文件,例如 CSV。Awk 条件和命令(包含在单引号之间并以字母开头NR
)对文本文件的每一行执行。(隐式循环。)
要全面学习 Awk,我强烈推荐Grymoire 教程,但我将解释上述命令中使用的 Awk 功能。
-v
Awk的标志允许我们在执行 Awk 命令之前(针对文件的每一行)设置一个 Awk 变量(一次)。在这种情况下,我们设置x
为10
.
NR
是一个特殊awk中变量指的是“ Ñ的电流的棕土- [R的eCord”。换句话说,它是我们在任何特定循环中查看的行号。
(注意,这是可能的,但不寻常的,使用不同的“ [R的eCord小号eparator”不是一个换行符的默认情况下,设置RS
。 这是与记录分隔玩的例子。)
awk 脚本通常由条件(大括号外)和动作(大括号内)组成。可以有复合条件和复合动作,还有一个默认条件(真)和一个默认动作(打印),但我们需要不用管那些。
这里的条件是,“这是第 10 行吗?” 如果是这种情况,我们会以非零退出状态退出,这在 shell 脚本中意味着“不成功的命令终止”。
因此,此 Awk 命令成功退出的唯一方法是在到达第 10 行之前到达文件末尾。
所以如果 awk 脚本成功退出,说明你的文件少于十行。
下一次-exec
调用(如果您删除echo
)将find
通过运行删除每个文件(在评估的初选时得到那么远):
rm -f ./somefilename
Run Code Online (Sandbox Code Playgroud)
假设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 {} +
Run Code Online (Sandbox Code Playgroud)
删除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
Run Code Online (Sandbox Code Playgroud)
(再次,echo
高兴时删除)。
与perl
以下相同:
x=10 find . -type f -readable -exec perl -Tlne '
if ($. == $ENV{x}) {close ARGV}
elsif (eof) {print $ARGV; close ARGV}' {} +
Run Code Online (Sandbox Code Playgroud)
更换print
与unlink
是否幸福。