Shell 脚本将最旧的文件从一个目录移动到另一个目录

Shell 脚本将最旧的文件从一个目录移动到另一个目录

我是 shell 脚本新手。我正在寻找解决方案。我应该在我的目录中维护 10 个文件,以防任意数量的文件添加到该目录中。我只想将最旧的文件移动到其他目录。我为我的目录命名为 Work,为另一个目录命名为 Regular_archieve。我试过这个,

work = /home/balaji/work
regular_archieve = /home/balaji/regular_archieve
cd $work
for i in 'ls -t | sed -e '1,10d' | xargs -d '\n' rm -f'
do
 mv $i $regular_archieve
done
if [ls -t | wc -1 > 10 | mv /home/balaji/regular-archieve]
 then
   echo "more than 10 n files"
fi
mv $(ls -t /home/balaji/work | sed -e '1,10d' | tail - 1) /home/balaji/regular_archieve

但我无法将文件移动到另一个目录。

我收到此错误,

mv: cannot stat 'file' : No such file or directory

答案1

ls除了在终端中查看之外,将 的输出用于任何其他用途都不是一个好主意。看为什么不是解析ls(以及该怎么做)?。相反,使用find

find /home/balaji/work/ -type f -printf '%C@\t%p\0' |
  sort -z -k1,1 -r -n |
  cut -z -f2 |
  head -z -n 10 | 
  xargs -0r echo mv -t /home/balaji/regular_archive/

find这需要、sortcuttail和的 GNU 版本xargs(或者至少支持-zNUL 记录分隔符选项的其他版本)。

  • find用于列出所有常规文件的-printf '%C@\t%p\0'最后更改时间戳(%C@自 1970-01-01 00:00:00 以来的秒数)和文件名 ( )。%p字段由单个制表符 ( ) 分隔,每个记录由 NUL 字符 ( )\t分隔\0
  • find 的输出通过管道传输到 sort 中,以仅在第一个字段 ( ) 上-r按数字 ( ) 对文件进行反向排序 ( ) —— 即按时间戳。-n-k 1,1
  • sort 的输出通过管道传输到 cut 以删除时间戳字段(完成排序后我们不再需要它)
  • cut 的输出通过管道输入head以获得前十个条目
  • 最后,head 的输出通过管道传输xargs到运行mv命令。这使用了 mv 的 GNU-t扩展名,以便可以在文件名之前指定目标目录。

实际上,这是运行echo mv而不是运行mv,所以这是一次预运行。echo当你确定它会做你想做的事情时,就摆脱它。

注意:这将适用于任何文件名,无论其中可能包含什么奇怪和烦人的字符(例如空格、换行符、shell 元字符等)。此外,该file命令还有许多其他选项,可用于细化搜索条件。


如果您有旧版本的 GNU coreutils(即 < 版本 8.25),则cutheadtail不会有-z选项。你可以用awk它代替。例如

find /home/balaji/work/ -type f -printf '%C@\t%p\0' |
  sort -z -k1,1 -r -n |
  awk -F '\t' 'BEGIN {RS=ORS="\0"}; NR<=10 { $1=""; $0=$0; $1=$1 ; print }' |
  xargs -0r echo mv -t /home/balaji/regular_archive/

或者,您可以使用perl而不是awk

 perl -F'\t' -0lane 'if ($. <= 10) {delete $F[0]; print @F}'

答案2

我将忽略代码中明显的语法错误,并假设您希望在目录中保留最近修改的十个文件~/work。我还假设您有zsh可用的 shell。

以下zshshell 脚本会将除最近修改的十个文件之外的所有文件从 移动~/work~/regular_archieve

#!/bin/zsh

mv -i $HOME/work/*(.om[11,-1]) $HOME/regular_archieve

脚本中的单个命令将最近修改的十个文件保留在 中~/work,并将其余文件移动到 中~/regular_archieve。它使用特定的通配模式mv并在其帮助下完成此操作zsh。该模式*(.om[11,-1])将扩展到需要移动的常规文件(不会匹配任何目录)。它om按修改时间戳对文件进行排序,并且[11,-1]在此排序列表中挑选出文件名 11 到最旧的文件。开头的点全局限定符 .om[11,-1]使 glob 只匹配常规文件。

如果目录中可能有数千个文件,则可能会生成“参数列表太长”错误。在这种情况下,请使用循环单独移动文件:

#!/bin/zsh

for pathname in $HOME/work/*(.om[11,-1]); do
    mv -i $pathname $HOME/regular_archieve
done

答案3

我找到了该问题的另一个答案。最好用寻找命令而不是使用LS命令。这将有助于找到最旧的文件并可以使用MV命令移动到另一个目录。

mv $(find /home/balaji/work/ -type f -printf '%T+ %p\n' | sort | head -1) /home/balaji/regular_archieve

find– 在目录层次结构中搜索文件。

/home/balaji/work/– 搜索位置。

/home/balaji/regular_archieve/- 目标位置。

type -f– 仅搜索常规文件。

-printf ‘%T+ %p\n’– 打印文件的最后修改日期和时间,以 + 符号分隔。 (例如 2015-07-22+13:42:40.0000000000)。这里,%p表示文件名。 \n 表示换行。

sort | head -n 1– sort 命令对输出进行排序,并将输出发送到 head 命令以显示最旧的文件。这里,-n 1 表示只有一个文件,即最旧的文件。

相关内容