关于原始问题 variation , in case the matching files need to be processed individually or collected in a shell array :
# One by one, in a shell loop (POSIX-compliant):
ls -tp | grep -v '/$' | tail -n +6 | while IFS= read -r f; do echo "$f"; done
# One by one, but using a Bash process substitution (<(...),
# so that the variables inside the `while` loop remain in scope:
while IFS= read -r f; do echo "$f"; done < <(ls -tp | grep -v '/$' | tail -n +6)
# Collecting the matches in a Bash *array*:
IFS=$'\n' read -d '' -ra files < <(ls -tp | grep -v '/$' | tail -n +6)
printf '%s\n' "${files[@]}" # print array elements
85
当前目录中有目录时,所有这些答案都会失败 . 这是有效的:
find . -maxdepth 1 -type f | xargs -x ls -t | awk 'NR>5' | xargs -L1 rm
#!/bin/bash
# sed cmd chng #2 to value file wish to retain
cd /opt/depot
ls -1 MyMintFiles*.zip > BigList
sed -n -e :a -e '1,2!{P;N;D;};N;ba' BigList > DeList
for i in `cat DeList`
do
echo "Deleted $i"
rm -f $i
#echo "File(s) gonzo "
#read junk
done
exit 0
ls -C1 -t | awk 'NR>5' | sed -e "s/^/rm '/" -e "s/$/'/" | sh
基本逻辑:
按时间顺序获取文件列表,一列
得到除前5之外的所有(本例中n = 5)
第一版:发送给rm
第二版:生成一个可以正确删除它们的脚本
2
我把它变成了一个bash shell脚本 . 用法: keep NUM DIR 其中NUM是要保留的文件数,DIR是要擦除的目录 .
#!/bin/bash
# Keep last N files by date.
# Usage: keep NUMBER DIRECTORY
echo ""
if [ $# -lt 2 ]; then
echo "Usage: $0 NUMFILES DIR"
echo "Keep last N newest files."
exit 1
fi
if [ ! -e $2 ]; then
echo "ERROR: directory '$1' does not exist"
exit 1
fi
if [ ! -d $2 ]; then
echo "ERROR: '$1' is not a directory"
exit 1
fi
pushd $2 > /dev/null
ls -tp | grep -v '/' | tail -n +"$1" | xargs -I {} rm -- {}
popd > /dev/null
echo "Done. Kept $1 most recent files in $2."
ls $2|wc -l
17 回答
需要GNU查找-printf,GNU排序为-z,GNU awk为“\ 0”,GNU xargs为-0,但处理带有嵌入换行符或空格的文件 .
删除除10个最新(最近的)文件之外的所有文件
如果少于10个文件没有删除文件,您将拥有:错误头:非法行数 - 0
To count files with bash
在Debian上运行(假设它在我得到的其他发行版上是相同的:rm:无法删除目录`..'
这很烦人..
无论如何,我调整了上面的内容,并在命令中添加了grep . 在我的情况下,我在目录中有6个备份文件,例如file1.tar file2.tar file3.tar等我想删除最旧的文件(在我的情况下删除第一个文件)
我运行的删除最旧文件的脚本是:
ls -C1 -t | grep文件| awk'NR> 5'| xargs rm
这(如上所述)删除了我的第一个文件,例如file1.tar这也留下了file2 file3 file4 file5和file6
更简单的thelsdj答案:
ls -tr显示所有文件,最早的文件(-t最新的第一个,-r反向) .
head -n -5显示除最后5行之外的所有行(即5个最新文件) .
xargs rm为每个选定的文件调用rm .
我意识到这是一个老线程,但也许有人会从中受益 . 此命令将在当前目录中查找文件:
这比以前的一些答案更加健壮,因为它允许将搜索域限制为匹配表达式的文件 . 首先,找到符合您想要的任何条件的文件 . 打印带有时间戳的文件 .
接下来,按时间戳排序:
然后,从列表中删除最近的4个文件:
grab 第二列(文件名,而不是时间戳):
然后将整个内容包装成for语句:
这可能是一个更详细的命令,但我有更好的运气能够针对条件文件并执行更复杂的命令 .
现有答案存在的问题:
无法处理带有嵌入空格或换行符的文件名 .
对于直接在不带引号的命令替换(
rm
...`` )上调用rm
的解决方案,会增加意外通配的风险 .无法区分文件和目录(即,如果目录恰好是最近修改的5个文件系统项目之一,则实际上保留少于5个文件,并且将
rm
应用于目录将失败) .wnoise's answer解决了这些问题,但解决方案是GNU特定的(并且非常复杂) .
这是一个实用的, POSIX-compliant solution 只有 one caveat :它无法处理带有嵌入换行符的文件名 - 但我不认为这对大多数人来说是一个现实问题 .
为了记录,这里解释为什么解析ls输出通常不是一个好主意:http://mywiki.wooledge.org/ParsingLs
以上是 inefficient ,因为
xargs
必须为每个文件名调用rm
一次 .您的平台的
xargs
可能允许您解决此问题:如果您有 GNU xargs ,请使用
-d '\n'
,这会使xargs
将每个输入行视为一个单独的参数,但会传递尽可能多的参数,以适应命令行:-r( - no-run-if-empty)确保在没有输入的情况下不调用rm .
如果你有 BSD xargs (包括在 OS X 上),你可以使用
-0
来处理NUL
分离的输入,首先将换行符转换为NUL
(0x0
)字符,这也会一次传递(通常)所有文件名(也适用于GNUxargs
) ):Explanation:
ls -tp
打印文件系统项目的名称,按照最近修改的顺序排序,按降序排列(最近修改的项目)(-t
),目录打印有尾随/
以将其标记为(-p
) .grep -v '/$'
然后通过省略(-v
)具有尾随/
(/$
)的行来清除结果列表中的目录 .警告:由于指向目录的符号链接在技术上本身不是目录,因此不会排除此类符号链接 .
tail -n +6
跳过列表中的前5个条目,实际上返回除了最近修改的5个文件之外的所有文件(如果有的话) .请注意,为了排除
N
文件,必须将N+1
传递给tail -n +
.xargs -I {} rm -- {}
(及其变体)然后在rm
上调用所有这些文件;如果根本没有匹配,xargs
将不会做任何事情 .xargs -I {} rm -- {}
定义占位符{}
,它代表每个输入行的整体,因此rm
然后为每个输入行调用一次,但是处理了嵌入空格的文件名正确 .在所有情况下
--
确保碰巧以-
开头的任何文件名都不会被rm
误认为是选项 .关于原始问题 variation , in case the matching files need to be processed individually or collected in a shell array :
当前目录中有目录时,所有这些答案都会失败 . 这是有效的:
这个:
在当前目录中有目录时有效
尝试删除每个文件,即使无法删除上一个文件(由于权限等)
当当前目录中的文件数量过多而
xargs
通常会让你搞砸时安全失败(
-x
)不适合文件名中的空格(也许你使用的是错误的操作系统?)
在Sed-Onliners中找到了有趣的cmd - 删除了最后3行 - 它完美的另一种方式来剥皮猫(好吧没有)但想法:
此版本支持带空格的名称:
删除目录中除最新文件的5个(或任何数量)之外的所有文件 .
忽略换行符会忽略安全性和良好的编码 . wnoise有唯一的好答案 . 这是他的一个变体,它将文件名放在数组$ x中
我需要为busybox(路由器)提供一个优雅的解决方案,所有xargs或阵列解决方案对我来说都是无用的 - 那里没有这样的命令 . find和mtime不是正确的答案,因为我们正在谈论10个项目,而不一定是10天 . Espo的答案是最短,最干净,也可能是最不可逆的答案 .
空格出错以及没有要删除的文件都是以标准方式解决的:
更有教育意义的版本:如果我们使用awk的话,我们可以做到这一切 . 通常,我使用此方法将变量从awk传递(返回)到sh . 当我们阅读所有无法完成的时间时,我不同意:这是方法 .
.tar文件的示例,文件名中的空格没有问题 . 要测试,请将“rm”替换为“ls” .
说明:
ls -td *.tar
列出按时间排序的所有.tar文件 . 要应用于当前文件夹中的所有文件,请删除"d *.tar"部分awk 'NR>7...
跳过前7行print "rm \"" $0 "\""
构造一条线:rm "file name"eval
执行它由于我们使用
rm
,我不会在脚本中使用上面的命令!更明智的用法是:在使用
ls -t
命令的情况下,对这样的愚蠢示例不会造成任何伤害:touch 'foo " bar'
和touch 'hello * world'
. 并非我们在现实生活中创建具有此类名称的文件!边注 . 如果我们想以这种方式将变量传递给sh,我们只需修改print(简单形式,不容许空间):
将变量
VarName
设置为$1
的值 . 可以一次创建多个变量 . 这VarName
成为普通的sh变量,之后通常可以在脚本或shell中使用 . 所以,用awk创建变量并将它们返回给shell:如果文件名没有空格,这将起作用:
如果文件名确实有空格,那就像
基本逻辑:
按时间顺序获取文件列表,一列
得到除前5之外的所有(本例中n = 5)
第一版:发送给rm
第二版:生成一个可以正确删除它们的脚本
我把它变成了一个bash shell脚本 . 用法:
keep NUM DIR
其中NUM是要保留的文件数,DIR是要擦除的目录 .按修改时间列出文件名,引用每个文件名 . 排除前3(最近3) . 删除剩余的 .
在mklement0的有用评论之后编辑(谢谢!):更正了-n 3参数,并注意如果文件名包含换行符和/或目录包含子目录,这将无法按预期工作 .
随着zsh
假设您不关心当前目录,并且您将不会有超过999个文件(如果需要,请选择更大的数字,或创建while循环) .
在
*(.om[6,999])
中,.
表示文件,o
表示排序顺序,m
表示修改日期(对于访问时间为a
或对于inode更改为c
),[6,999]
选择一个文件范围,因此不是5第一 .