删除少于x行的文件的快速方法


10

在bash中删除x行以下的目录中的所有文件的快速但又不太复杂的方法是什么?

Answers:


10

这是一个POSIX解决方案,应该很容易理解:

find . -type f -exec awk -v x=10 'NR==x{exit 1}' {} \; -exec echo rm -f {} \;

就像在斯蒂芬(Stephane)的答案中一样echo在满意时将其删除。


为Unix / Linux的新手编写的说明:

.代表当前目录。 find在中以递归方式查找文件和目录.,并可以对其进行处理。

-type是以下之一find初选 ; 该测试将对(在内.)递归找到的每个文件和目录执行,并且仅当结果为“ true”时,才评估行中的其余主键。

在这种情况下,只有在处理常规文件而不是目录或其他内容(例如块设备)时,我们才继续。


-exec主要对象(find)调用一个外部命令,并且仅在该外部命令成功退出(退出状态为“ 0”)时才继续到下一个主要对象。该命令{}将替换为find命令“考虑”的文件名。因此,第一个-exec调用等效于依次对每个文件执行的以下shell命令:

awk -v x=10 'NR==x{exit 1}' ./somefilename

Awk本身就是一门完整的语言,旨在处理带分隔符的文本文件,例如CSV。对于NR文本文件的每一行都执行Awk条件和命令(包含在单引号中,并以字母开头)。(隐式循环。)

要完全学习Awk,我强烈建议您使用Grymoire教程,但我将解释上述命令中使用的Awk功能。


-vAwk 的标志允许我们在Awk命令执行之前(针对文件的每一行)设置Awk变量(一次)。在这种情况下,我们设置x10


NR是一个特殊awk中变量指的是“ Ñ的电流的棕土- [R的eCord”。换句话说,它是我们在循环的任何特定遍历中所查看的行号。

(注意,这可能的,但不寻常的,使用不同的“ [R的eCord 小号 eparator”不是一个换行符的默认情况下,设置RS这是与记录分隔玩的例子。


Awk脚本通常由条件(大括号外)和动作(大括号内)组成。可以有复合条件和复合动作,并且有默认条件(真)和默认动作(打印),但是我们需要不用理会那些。

这里的条件是“这是第十行吗?” 在这种情况下,我们以非零退出状态退出,这在Shell脚本中表示“命令终止失败”。

因此,此Awk命令将成功退出的唯一方法是,如果在到达第10行之前到达文件的末尾。

因此,如果Awk脚本成功退出,则意味着您的文件少于10行。


下一个-exec调用(如果您删除echo)将find通过运行以下命令删除每个文件(在的primaries 评估中获得的优势):

rm -f ./somefilename

5

假设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行,wcrm为每个文件运行一个(可能一个)命令。

使用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}' {} +

如果满意,请替换printunlink


1.最后sh是什么?2. wc -l < "$file"比...快wc -l "$file"吗?3. sh如何知道$x在调用Bash shell中定义的的值?

3
@tomas,最后sh是该内嵌脚本的内容$0,例如用于错误消息。wc -l "$file"会打印我们在此处不需要的文件名,wc即使文件无法打开也可以运行。$x被导出到findx=10 find...)本身传递给sh
斯特凡Chazelas

谢谢!但是我想我在OSX上遇到的这个错误意味着我的Bash版本不支持-可读标志?find: -readable: unknown primary or operator
durrrutti '16

1
@durrrutti,还不至于bashbash只是命令行解释器,而是find实现的解释器。-readable是GNU扩展,在OS / X中不可用find。它仅用于限制可读文件(您将无法获得不可读文件的行数)。您可以为第一个省略它,然后wc为不可读的文件打开文件时会得到错误消息。
斯特凡Chazelas

@StéphaneChazelas,这个答案是如此棘手,我不禁要问:我的答案有没有遗漏任何边缘情况?:)
通配符

2

为了完整起见,除了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) 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.