我的电子邮件帐户已通过60GB的电子邮件,目前在使用电子邮件客户端存档去年(2011年)的电子邮件时遇到很多麻烦。
通过终端,我尝试使用find来查找2011-01-01和2011-12-31之间的文件,但无济于事。
如何找到两个日期之间的文件?
如果相关的话,最终目标将是一批将与日期间隔匹配的找到的每个文件移动到一个文件夹的批处理。
我的电子邮件帐户已通过60GB的电子邮件,目前在使用电子邮件客户端存档去年(2011年)的电子邮件时遇到很多麻烦。
通过终端,我尝试使用find来查找2011-01-01和2011-12-31之间的文件,但无济于事。
如何找到两个日期之间的文件?
如果相关的话,最终目标将是一批将与日期间隔匹配的找到的每个文件移动到一个文件夹的批处理。
Answers:
您可以使用以下脚本:
#!/bin/bash
for i in $(find Your_Mail_Dir/ -newermt "2011-01-01" ! -newermt "2011-12-31"); do
mv $i /moved_emails_dir/
done
find
不应在这样的shell for
循环中处理的输出。-exec
,-execdir
或-print0 | xargs
通常应改为使用;另一种可能的解决方案for
是临时设置,通常不那么理想,但确实允许使用循环,IFS
因此不能将空格识别为字段分隔符。
find
为exec
?您介意添加一个解决空格使用问题的答案吗?非常感激。
exec
命令。使用find
命令执行-exec
操作mv
,或者执行任何操作,如我发布的答案中所述。当find
... -exec
使用找到的路径名运行命令时,它不使用外壳程序,因此空格不会触发单词拆分或globlob。(您可能想对特定情况发布一个新问题,或者确切地问您想知道什么。)
Bash查找两个日期之间的文件:
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
如Subv3rsion和Eric Leschinski的答案所示,-newermt
谓词选择的文件的修改时间比指定为其操作数的日期(和可选时间)更新的时间最近。查找文件
srcdir
(即,包括其子目录,子目录等)destdir
...您可以运行:
find srcdir -type f -newermt 2014-08-31 ! -newermt 2014-09-30 -exec mv -i {} destdir/ \;
在-exec
表达式中,find传递代替找到的文件名{}
。;
表示-exec
已提供了要运行的命令及其参数(如果传递了后续表达式以在该特定-exec
谓词的参数之后查找,请参见以下示例)。;
必须进行转义,\;
这样外壳程序就不会对其进行特殊解释。(不带\
,;
将结束整个find
命令,与换行符相同。即使此find
命令在此-exec
表达式之后没有任何内容,但不传递;
参数仍然是语法错误。)
如果您只想列出文件(如果您不确定旧电子邮件的存储方式或可能存在的其他文件,建议这样做),然后忽略-exec
所有内容。(对于电子邮件,通常将来自不同日期的电子邮件存储在同一文件中;对于处于此处问题所述情况的某人,我建议在移动任何文件之前调查一下它们的存储方式。)如果要同时打印其名称并移动他们,添加-print
之前-exec
。
mv -i
提示何时文件将在目标位置被覆盖,例如在以下情况下发生的情况:
srcdir
在相同的find
操作过程中已移动了具有相同名称但来自的另一个子目录的文件,或者srcdir
在同一find
操作的某个位置创建了一个同名文件,但是一旦find
遍历另一个子目录,很快就可以找到该文件。rm
:您还可以使用其他选项来处理具有重复名称的文件。
-i
(即),通常不会提示您批准,但如果目标文件是只读的,则会这样做。(有时甚至可以成功覆盖只读文件,例如运行该文件的用户拥有该文件。)mv {} destdir/
mv
mv
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
由于与目的地不同的原因而无法复制文件,则会错误地发出警告,并退出报告成功。这似乎不太可能,但我不确定这是不可能的。它还可能会出现竞争状况:如果在移走旧文件之后以及在检查到看看是否已将其删除。(考虑到该应用程序,我怀疑这两个问题是否会真正发生。)在执行之前,可以将其重写以检查目标位置移动文件而不是移动文件:竞争条件将与新创建的目标文件而不是源文件有关。而且,虽然find
或mv
(或[
,尽管不应出现)报告的错误和警告将写入标准错误,但我们的...skipped (exists in...
警告会写入标准输出。通常,两者都出现在您的终端上,但是如果您编写脚本,这可能很重要。
我将该命令分为两行,以方便阅读。可以通过这种方式运行,也可以删除\
和换行符(即换行符)。
find
命令如何工作?find
谓词可以是用于返回值的测试(如-type
和-newermt
),或通常用于其副作用的动作(如-print
和-exec
)。
如果在表达式之间未提供任何运算符(例如-a
for 和 for ,-o
for 或),则表示-a
为隐含的。find
采用短路评价为和和或。(即)仅当p和q表达式均为true时才为true,因此如果p为false 则不需要对q进行求值。尽管我们通常不以这些术语来考虑它,但是这就是为什么对于随后的动作或要评估的测试,测试必须为真。例如,假设出现在目录中。它的计算结果为false,因此以后可以跳过所有内容。p q
p -a q
find
-type f
与测试一样,动作的评估结果也为真或假。以这种方式,-exec
报告执行的命令是否退出,报告成功(true)或失败(false)。我们使这一系列-exec
表达式与隐式和相连:
-exec mv -n {} destdir/ \; -exec [ -f {} ] \; -exec printf "\`%s' skipped (exists in \`%s')\\n" {} destdir \;
这将尝试移动文件,如果mv
报告失败,则停止。如果由于其他原因导致文件未移动,我们不想警告正确跳过的文件。
但是,如果它成功了,它然后运行该[
命令。Like find
,[
支持作为参数传递的其自身类型的表达式。[ -f {} ]
检查之后的操作数-f
(find
代替传递给它{}
)是否存在(并且是常规文件),并返回true / success或false / failure。
(最好将许多命令的退出状态解释为表示成功或失败,但是[
通常将其存在状态最好解释为对或错。)
如果[
返回false,则文件不见了,因此被移动了,因此无需执行任何操作。但是,如果[
返回false,则该文件仍然存在。然后find
计算下一个-exec
表达式,该表达式将打印警告消息。
man find
和GNU Findutils参考手册man mv
和GNU Coreutils参考手册(尤其是11.4 mv
:移动(重命名)文件)man \[
和16.3测试:在Coreutils文档中检查文件类型并比较值。当您使用时,/usr/bin/[
而不是Shell的[
内置)(而不是Shell的内置函数)find
运行-exec [
。-exec ... +
使用mv -t
。