如何使用“查找”查找两个日期之间的文件?

如何使用“查找”查找两个日期之间的文件?

我有一个电子邮件帐户,其中的电子邮件已超过 60GB,目前我使用电子邮件客户端存档去年(2011 年)的电子邮件遇到了很多麻烦。

通过终端,我尝试使用寻找来定位 2011-01-01 至 2011-12-31 之间的文件,但无济于事。

如何查找两个日期之间的文件?

如果相关的话,最终目标将是一个批处理,将找到的每个文件(与日期间隔匹配)移动到一个文件夹中。

答案1

Bash 查找两个日期之间的文件:

通过以下方式在 GNU findutils 4.9.0 源代码上进行测试:https://www.gnu.org/software/findutils/

find . -type f -newermt 2010-10-07 ! -newermt 2014-10-08

返回时间戳在 2010-10-07 之后和 2014-10-08 之前的文件列表

Bash 查找 15 分钟前到现在的文件:

find . -type f -mmin -15

返回时间戳在 15 分钟之后但在现在之前的文件列表。

Bash 查找两个时间戳之间的文件:

find . -type f -newermt "2014-10-08 10:17:00" ! -newermt "2014-10-08 10:53:00"

返回时间戳介于2014-10-08 10:17:00和之间的文件2014-10-08 10:53:00

答案2

您可以使用这个脚本:

#!/bin/bash
for i in $(find Your_Mail_Dir/ -newermt "2011-01-01" ! -newermt "2011-12-31"); do
  mv $i /moved_emails_dir/
done

答案3

移动文件,并在名称重复时提示用户:

作为Subv3rsion 的Eric Leschinski 的答案显示,-newermt谓词选择比其操作数指定的日期(和可选时间)更近修改的文件。要查找文件

  • 任何地方srcdir(即包括其子目录、它们的子目录等)
  • 最后修改于(例如)2014 年 9 月
  • 并移动它们destdir

...你可以运行:

find srcdir -type f -newermt 2014-08-31 ! -newermt 2014-09-30 -exec mv -i {} destdir/ \;

-exec表达式中,find 传递找到的文件名来代替{};表示-exec要运行的命令及其参数都已提供(以防后续表达式在该特定-exec谓词的参数之后传递给 find - 请参阅下面的示例)。;必须转义为,\;以便 shell 不会对其进行特殊解释。(如果没有\;将结束整个find命令,其作用与换行符相同。即使此find命令在此表达式后没有任何内容-exec,未能传递;参数仍是语法错误。)

如果您只想列出文件(如果您不确定旧电子邮件的存储方式或可能存在哪些其他文件,建议这样做),请省略-exec其右侧的所有内容。(对于电子邮件,通常不同日期的电子邮件存储在相同的文件;对于这里问题中描述的情况的人,我建议在移动任何文件之前调查它们的存储方式。)如果您想同时打印它们的名称并移动它们,请-print在之前添加-exec

mv -i每当文件在目标位置被覆盖时都会提示,例如在以下情况下会发生:

  • 先前备份中存在同名文件,或者
  • 同名但来自不同子目录的文件srcdir已在同一find操作中被移动,或者
  • (最不可能)在某处创建了一个同名文件srcdir在同一操作过程中,原始文件被移动后,一旦遍历不同的子目录find,很快就会被发现。find

其他调用方式mv

对于如何处理具有重复名称的文件,您还有其他选择。

  • 如果没有-i(即),通常不会提示批准,但如果目标文件是只读的则会提示批准。(有时甚至可以成功覆盖只读文件,例如运行它的用户拥有该文件。)mv {} destdir/mvmv
  • 如果您甚至不想要这种程度的交互性,并且mv总是想(尝试)覆盖同名文件,请使用mv -f
  • 相反,如果您想在已有同名目标文件的情况下跳过源文件,请使用mv -n
  • mv接受-b--backup标志以自动重命名目标中已存在的同名文件。默认情况下,~添加以生成备份名称,如果目标中已存在同名文件和备份文件,则将覆盖备份文件。此默认值可以通过调用时传递的选项mv和环境变量覆盖。请参阅man mv有关详细信息和示例,请参阅下面的。

移动文件并创建备份以防名称重复:

要移动所有文件,使用后缀备份具有重复名称的文件~,并在文件已存在时使用编号后缀(以避免覆盖任何内容),请运行:.~n~.~

find srcdir -type f -newermt 2014-08-31 ! -newermt 2014-09-30 -exec mv --backup=existing {} destdir/ \;

如果您跳过了具有重复名称的文件并且想知道是哪些文件:

如果您使用mv -n并想知道哪些文件未被移动,因为有另一个同名文件,最好的方法可能是再次运行原始find命令,而不使用-exec其右侧的和所有内容。这将打印它们的名称。
它还将打印自您运行原始命令以来创建的任何匹配文件的名称find .... -exec ...,但对于此应用程序,通常不会有,因为您要查找具有旧修改时间的文件。可以使用和其他机制为文件提供比其实际年龄更早的修改时间戳touch,但在这种情况下,在您不知情的情况下似乎不太可能发生这种情况。

立即知道由于名称重复而跳过的文件:

mv -n不报告,也不返回任何特殊退出代码,当它避免移动文件时。因此,如果您想在find运行时立即获知跳过的文件,则必须为此执行单独的步骤。一种方法是:

find srcdir -type f -newermt 2014-08-31 ! -newermt 2014-09-30 -exec mv -n {} destdir/ \; \
    -exec [ -f {} ] \; -exec printf "\`%s' skipped (exists in \`%s')\\n" {} destdir \; 

一些可能不太重要的技术考虑:如果mv由于与目标位置存在文件不同的原因而无法复制文件,则会发出错误警告并退出报告成功。这似乎不太可能,但我不确定这是否不可能。它还可能遭受竞争条件:如果在旧文件被移动后和检查是否被删除之前的很短时间内在同一位置创建了同名的新文件,它会在根本没有任何实际错误的情况下发出警告。(考虑到应用程序,我怀疑这两个问题都不会真正发生。)可以重写它以检查目标移动文件而不是之后:那么竞争条件将与新创建的目标文件有关,而不是与源文件有关。而findmv(或[,尽管不应该有)报告的错误和警告将写入标准误差,我们的...skipped (exists in...警告被写到标准输出。通常两者都会出现在您的终端上,但如果您正在编写脚本,这可能很重要。

我把这个命令分成两行,以便于阅读。可以这样运行,或者你可以删除\和换行符(即换行符)。

该命令如何find工作?

find谓词可以是测试(如-type-newermt),用于它们的返回值,或行动(如-print-exec),它们是经常因其副作用而使用。

当没有操作符(-a例如-o为了或者) 在表达式之间提供,-a是隐含的。find使用短路评估为了或者. (即)仅当p qp -a q表达式都是真的,所以无需评估,如果为假。尽管我们通常不会这样想,但这就是为什么测试必须为真,才能对后续操作或测试进行评估。例如,假设find遇到一个目录。它的评估结果-type f为假,因此它可以跳过之后的所有内容。

与测试一样,操作也会评估为真或假。这样,-exec报告执行的命令是否成功(真)或失败(假)。我们有这一系列-exec表达式,它们与隐式

-exec mv -n {} destdir/ \; -exec [ -f {} ] \; -exec printf "\`%s' skipped (exists in \`%s')\\n" {} destdir \;

这会尝试移动文件,如果mv报告失败,则停止。如果文件未移动是因为其他问题,我们不想警告正确跳过的文件。

但如果成功,它就会运行命令[。与 一样find[支持将其自身类型的表达式作为参数传递。[ -f {} ]检查 之后的操作数-f(由find代替传递给它{})是否存在(并且是常规文件),并返回 true/成功或 false/失败。
(许多命令的退出状态最好解释为表示成功或失败,但[的存在状态通常最好解释为 true 或 false。)

如果[返回 false,则文件已消失,因此文件已被移动,因此无需执行任何操作。但如果[返回 false,则文件仍在那里。然后find计算下一个-exec表达式,打印警告消息。

进一步阅读

相关内容