我如何抓取目录中的第一个子文件夹并将其删除?
我发现了一个脚本来监视可用磁盘空间。
它发送警报电子邮件,如果空间不足,但我也想删除一些不需要的东西。
我有一个备份文件夹,用于保存每日和每月的备份。 我想删除第一个文件夹,因为这总是最老的,但我不知道最老的备份的名称。
我的文件夹没有Jan-May和Dec:
06-01 07-01 08-01 09-01 10-01 11-01 Friday Monday Saturday Sunday Thursday Tuesday Wednesday
如何删除第一个文件夹“06-01”而不知道它的名字?
如果你想find关于字母数字顺序的第一个子文件夹 (那要注意,取决于你的本地设置),你可以使用这个小小的Bash片段:
shopt -s nullglob shopt -u dotglob a=( */ ) echo "${a[0]}"
这只会回应关于Bash的字母数字sorting的第一个子文件夹 。
如果你想删除它,添加几个警卫:
shopt -s nullglob shopt -u dotglob a=( */ ) [[ -d "${a[0]}" ]] && echo rm -rfv -- "${a[0]}"
现在,我不确定我会亲自在生产服务器上使用它。 这取决于我是如何确定目录的内容(以及如何确定我是由备份 )。
shopt -s nullglob和shopt -u dotglob在这里是为了避免一些愚蠢的错误,如果这些错误被设置的话。 另外,请注意报价,不要改变他们。
哦,我在公司面前留下了一个echo 。 只有当你确定这个工作正如你所期望的那样,经过多次testing之后,才能删除它。 作为一个单行:
shopt -s nullglob; shopt -u dotglob; a=( */ ); [[ -d "${a[0]}" ]] && echo rm -rfv -- "${a[0]}"
如果要指定子文件夹的path,只需将a=( */ )语句replace为:
a=( /path/to/folder/*/ )
确保你把一个绝对path,并且以*/结尾(带有斜线)。 如果您的path中有空格,请按如下所示使用引号:
a=( '/path with/spaces to/folder/'*/ )
(观察*/如何在引用部分之外,并且在结束引号和*/之后没有空格)。
现在,如果你真的想确定最老的子文件夹(如果有几个年龄相同的话,有一定的不确定性),你可以(不寒而栗)按照相反的顺序parsing按时间sorting的ls的输出,并把它取出来,如下所示:
ls -1tr --group-directories-first /path/to/folder | head -1 | xargs echo rm -rfv
但是如果没有目录(而不是删除最老的文件 ),则会失败,如果有文件包含空格或有趣的符号,则失败。 不要这样做。
你可以用ls */而不用-d选项列出目录的内容:
ls -1dtr path/to/folder/*/ | head -1 | xargs echo rm -rfv
但如果名称中有空格,这将会惨败。 不要这样做。
然后你可以尝试通过使用ls的-Q选项来解决这个问题(即引用输出):
ls -1dtQr path/to/folder/*/ | head -1 | xargs echo rm -rfv
但是如果文件名中有引号或换行符,则会失败。 不要这样做。
然后,你会尝试xargs -0选项:
ls -1dtQr path/to/folder/*/ | head -1 | xargs -0 echo rm -rfv
但如果文件名中有换行符,则失败。 不要这样做。
那你可以… 停下来!
如果你真的想要一个100%的防弹方法,虽然这可能不是最有效的,但是如果安全是你的首要任务,那么这将是适合你的,这里有一个可能性(在Bash中):
shopt -s nullglob shopt -u dotglob where="/path with spaces is ok/to/folder" for i in "$where"/*/; do if ! find "$where" -mindepth 1 -maxdepth 1 \! -name '.*' -type d \! -newer "$i" \! -samefile "$i" -print | read; then echo rm -rfv -- "$i" break fi done
这不是最有效率的,但工作得很好:它循环遍历给定目录where所有(第一级)目录where并启动find来获取比目录i更早的(非隐藏的)目录,并且如果它发现它什么都不做; 如果它没有发现,那么我们会打破echo rm ,并打破循环。 副作用是将被删除的目录是Bash的字母数字顺序中最早和最早的。
你甚至可以制作一个很酷的脚本(称之为rm_oldest_dir ):
#!/bin/bash if [[ $1 = --serious ]]; then serious=() shift else serious=("echo") fi if [[ -z $1 ]]; then echo >&2 "You must provide an argument" exit 1 fi where=$1 if [[ ! -d $where ]]; then echo >&2 "\`$where' is not a directory" exit 1 fi shopt -s nullglob shopt -u dotglob for i in "$where"/*/; do if ! find "$where" -mindepth 1 -maxdepth 1 \! -name '.*' -type d \! -newer "$i" \! -samefile "$i" -print | read; then "${serious[@]}" rm -rfv -- "$i" if ((${#serious[@]})); then echo "*** Nothing has been removed. Call with option --serious to really remove. ***" fi break fi done
然后用作,例如,
$ mkdir Test $ cd Test $ mkdir oldest; sleep 1; mkdir lots_of_dirs{1..10} $ rm_oldest_dir . rm -rfv -- ./oldest/ *** Nothing has been removed. Call with option --serious to really remove. *** $ ls lots_of_dirs1 lots_of_dirs3 lots_of_dirs6 lots_of_dirs9 lots_of_dirs10 lots_of_dirs4 lots_of_dirs7 oldest lots_of_dirs2 lots_of_dirs5 lots_of_dirs8 $ rm_oldest_dir --serious . removed directory: `./oldest' $ ls lots_of_dirs1 lots_of_dirs2 lots_of_dirs4 lots_of_dirs6 lots_of_dirs8 lots_of_dirs10 lots_of_dirs3 lots_of_dirs5 lots_of_dirs7 lots_of_dirs9 $
整齐。
你可以把它放在你的crontab中
0 0 * * * rm_oldest_dir --serious "/path with spaces/to/where/you/want"
对此脚本的唯一攻击是我能想到的是,如果文件夹过多:Bash的通配符效率不高,太多的文件夹可能会导致很长一段时间的CPU使用率很高,最终会以堕胎结束。 更多的参与方法是基于文件的快速sorting,但是由于这篇文章已经太长,我将在这里结束。
干杯!
我不知道这个答案的第二部分是否真的在SF上占有一席之地。 如果没有,请让我知道在评论或downvote这个职位!