我是 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
这需要、sort
、cut
、tail
和的 GNU 版本xargs
(或者至少支持-z
NUL 记录分隔符选项的其他版本)。
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),则cut
也head
也tail
不会有-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。
以下zsh
shell 脚本会将除最近修改的十个文件之外的所有文件从 移动~/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 表示只有一个文件,即最旧的文件。