我的目录中有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 -ltAr
、ls -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/