如何从目录中选择文件夹中最旧的文件

如何从目录中选择文件夹中最旧的文件

我的目录中有n很多文件../in/。我希望从这些文件中处理最旧的文件并将其发送到../complete/目录。其余文件将发送到该../error/目录。有人可以帮忙吗?

答案1

要将最旧的文件复制到../complete

cp -v "$(find ../in -maxdepth 1 -type f -printf '%T@ %p\0' | sort -zn | \
  sed -zn '1s/[0-9,\.]\+ //p')" ../complete

要将除最旧的之外的所有内容复制到../error

find ../in -maxdepth 1 -type f -printf '%T@ %p\0' | sort -zn | \
  sed -zn '2,$s/[0-9,\.]\+ //p' | xargs -0 cp -vt ../error

解释:

  • find
    • -maxdepth 1仅下降1级;因此它不会重复搜索目录。
    • -type f仅匹配文件。
    • -printf '...'自定义输出格式。%T@给出文件的最后修改时间(时间戳),%p是文件的名称。注意\0最后。文件以空字节分隔打印,而不是换行分隔,因为换行可能是文件名中的字符,这会破坏命令。
  • sort -zn这将读取以空字节分隔 ( ) 的输出-z并按数字排序 ( -n)。
  • sed -zn读取以空字节分隔的输出。
    • 1将仅匹配第一行(第一个命令)并将2,$匹配所有其他行(第二个命令)
    • s/[0-9,\.]\+ //p将从输出中删除前导时间戳。
  • 仅从第二个命令:xargs -0 cp -vt ../error处理以空字节分隔 ( ) 的输出-0并调用cp -vt ../error所有输入,这会复制文件。

输出示例:

$ ls -lt ../in/
total 0
-rw-r--r-- 1 user user 0 Jun 24 08:18 file2
-rw-r--r-- 1 user user 0 Jun 24 08:18 file3
-rw-r--r-- 1 user user 0 Jun 24 08:18 file4
-rw-r--r-- 1 user user 0 Jun 24 08:18 file5
-rw-r--r-- 1 user user 0 Jun 24 08:17 file_oldest
$ cp -v "$(...)" ../complete
'../in/file_oldest' -> '../complete/file_oldest'
$
$ find ... | xargs ... ../error
'../in/file2' -> '../error/file2'
'../in/file3' -> '../error/file3'
'../in/file4' -> '../error/file4'
'../in/file5' -> '../error/file5'

答案2

要查找最旧的文件并将其移动到所需的目录,请使用:

# cd to ../in/

$ ls -lt | grep -v '^d' | tail -1 | awk '{print $NF}' | xargs -I '{}' mv '{}' ../complete/

现在最旧的文件已移出,您可以将所有文件移至../error/

$ mv -- * ../error/

如果您有任何以--.mv-

答案3

建立在拉胡尔的回答:

$ ls -ltr | grep -v '^d' | awk 'NR==2 {print $NF; exit}' | xargs -I '{}' mv -- '{}' ../complete/

笔记:

  • 你说你想对“最旧的文件”做一些事情。所有答案都假设您的意思是最近最少修改。如果你的意思是最近最少改变了, 这样说的;答案会略有不同。如果你的意思是最近已创建,你想要的在Unix中几乎是不可能的。
  • ls -lt(拉胡尔使用的)按修改日期/时间的顺序以长格式列出当前目录,最新的在前,最旧的在后。  ls -ltr是个r与此相反;最旧的排在最前面,最新的排在最后。
  • 如果您可能有名称以句点 (.),将A选项添加到ls;例如,ls -ltrA。 (选项的顺序并不重要;您可以使用ls -ltArls -lAtr、 或者,ls -ltr -A即使您愿意。)
  • 我撒了谎。ls目录的长列表总是total先有一行。在 中ls -ltr,最旧的条目位于第二线。
  • grep -v '^d'过滤掉目录(如果有)。
  • awk 'NR==2 { print $NF; exit }' 打印第二行(最旧的文件)的最后一个字段(文件名*),然后退出。

    • 这比 少了一个进程tail -1 | awk '{print $NF}'
    • 这可能会工作得更快,因为当awk退出时,ls也可能退出,并且您将避免生成整个目录的列表。
    • grep你可以通过这样做来消除

      ls -ltr | awk '! /^d/ { count++ } count==2 { print $NF; exit }'
      

      但我不建议这么做。过于复杂的脚本很难维护。

  • 之后--mv xargs命令中如果您有任何以 a 开头的文件名,则这是必需的-
  • 你其实并不需要xargs.您可以将上面的命令简化为

    $ mv -- $(ls -ltr | grep -v '^d' | awk 'NR==2 { print $NF; exit }') ../complete/
    

________
* 就像拉胡尔的答案一样,如果文件名包含空格或制表符,这将会失败 - 如果文件名包含换行符,情况会更糟。

如果您可能有名称以句点 (.),shopt -s dotglob在做之前做

$ mv -- * ../error/

相关内容