首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么这个脚本的工作效率很低?

为什么这个脚本的工作效率很低?
EN

Unix & Linux用户
提问于 2021-03-27 14:18:42
回答 1查看 60关注 0票数 0

我有以下bash脚本,它在OpenMediaVault上作为cron作业运行:

代码语言:javascript
复制
BACKUP_DIR='/srv/dev-disk-by-uuid-9EE055CFE055ADF1/Backup dir/'
BACKUP_FILE_PATH="/srv/dev-disk-by-uuid-9EE055CFE055ADF1/Backup dir/Backup [ashen] ($(date +%d-%m-%Y)).tar.gz"
SERVER_DIR=/var/lib/docker/volumes/49c9e5c53ea5b9c893c0a80117860da9b493484395c0$
MAX_BACKUPS_COUNT=4

tar -zcf "$BACKUP_FILE_PATH" $SERVER_DIR

cd "$BACKUP_DIR"

[[ $( ls | wc -l ) -gt $MAX_BACKUPS_COUNT ]] && rm "$(ls -t | tail -1)"

脚本的目的是在给定的位置创建一个.tar.gz备份,如果备份目录中有4个以上的文件,则删除最旧的备份(重点是只保留4个最近的备份)。最后一行/命令并不总是有效的。在终端中手动运行它可以正常工作,有时脚本会执行它,但有时它会停止,直到我手动尝试运行脚本/行,然后它似乎神奇地修复了自己一段时间。

有人知道为什么偶尔会停止执行最后一行吗?即使我看到备份正在创建。

EN

回答 1

Unix & Linux用户

回答已采纳

发布于 2021-03-27 17:56:21

如果任何文件名包含换行符,则脚本将失败。解析ls是一个很坏的主意,很可能失败。此外,您的脚本只会删除最近的文件。因此,如果有100个文件,您将留下99。您似乎期望它将删除除最新的4之外的所有内容,但是脚本的逻辑并不是这样工作的。

这里有一种替代方法,可以处理任意文件名,并实际删除除最新的4个文件之外的所有文件:

代码语言:javascript
复制
#!/bin/bash

## avoid using CAPS for local variable names in shell scripts
backup_dir='/srv/dev-disk-by-uuid-9EE055CFE055ADF1/Backup dir/'
backup_file_path="/srv/dev-disk-by-uuid-9EE055CFE055ADF1/Backup dir/Backup [ashen] ($(date +%d-%m-%Y)).tar.gz"
server_dir='/var/lib/docker/volumes/49c9e5c53ea5b9c893c0a80117860da9b493484395c0这里的工作是由stat命令和各种下游管道完成的。下面是命令所做工作的详细说明:stat --printf '%Y %n\0' "$backup_dir"/*tar.gz:它以秒为单位打印备份目录中所有.tar.gz文件的时代以来的文件名和文件年龄。为了能够用换行符(\n)处理文件名,我们需要用NULL (\0)结束每个条目。这就是输出的样子:$ tar.gz -printf '%Y‘*\0’\ tr '\n‘’1616867929 ./afile 5 tar.gz 1616868565 ./file 10 tar.gz 1616868560 ./file 1 tar.gz 1616868561 ./文件2 tar.gz 1616867927 ./文件3 tar.gz 1616867928 ./文件4 tar.gz 1616867930 ./文件6 tar.gz 1616868562 ./文件7 tar.gz 1616868563 ./文件8 tar.gz 1616868564 ./文件9 tar.gz在这个例子中,我将输出通过管道传送到tr '\0' '\n',这样可以看得清楚,但是在实际输出中,每个记录的末尾都有一个\0。sort -rznk1,1:上面stat的输出通过管道传输到sort,D18将按反向顺序(-r)对其进行数字排序,使用\0作为记录分隔符(-z),并且只考虑第一个字段(-k1,1),这是文件的历史。输出结果如下:$ stat --printf '%Y %n\0‘"$backup_dir"/*tar.gz排序-rznk1,1’tr '\0‘'\n’n‘1616868565 ./file 10 tar.gz 1616868564 ./file 9 tar.gz 1616868563 ./file 8 tar.gz 1616868562 ./file 7 tar.gz 1616868561 ./file 2 tar.gz 1616868560 ./file 1 tar.gz 1616867930 ./file 6 tar.gz 1616867929 ./afile 5 tar。1616867928 ./文件4 tar.gz 1616867927 ./文件3 tar.gztail -z -n +"$max_backups":命令tail -n +X将打印从X记录开始给它的最后一条记录。在这里,X是$max_backups变量,这就是为什么需要将该变量设置为要保留的文件数加上一个。-z允许tail处理终止为空的记录。现在,我们有要删除的文件列表,但它们也有它们的年龄,我们需要删除它:$ stat -printf '%Y %n\0‘“$backup_dir/*tar.gz -rznk1,1 -rznk1,1 tail -z -n +5区tr '\0’'\n‘1616868561 ./文件2 tar.gz 1616868560 ./文件1 tar.gz 1616867930 ./文件6 tar.gz 1616867929 ./afile 5 tar.gz 1616867928 ./file 4 tar.gz 1616867927 ./file 3 tar.gz .sed -z 's/^[0-9]* //':删除文件的年代,只留下名称。再一次,-z将处理终止为空的记录:$ stat --printf '%Y %n\0‘"$backup_dir"/*tar.gz /*tar.gz sort /*tar.gz sort -rznk1,1 -z -z -n +5 sed -z 's/^* //’AC.26 tr '\0‘\n’./file 2 tar.gz ./file 1 tar.gz ./file 6 tar.gz ./afile 5 tar.gz./file 4 tar.gz ./file 3 tar.gzxargs -0 rm -v:最后一步。这将删除文件,并且,再次,-z可以处理以空结尾的记录。重要的:脚本假定您使用的是GNU工具。开放式媒体库声称是Linux并运行Debian,所以它应该适用于您,但我从未使用过该系统,所以我无法确定。
## This needs to be set to the number of files you want to keep plus one,
## so that we can use tail -n $max_backups below.
max_backups=5

tar -zcf "$BACKUP_FILE_PATH" "$SERVER_DIR" 

## delete all but the newest 4 tar.gz files in the
## backup directory
stat --printf '%Y %n\0' "$backup_dir"/*tar.gz |
  sort -rznk1,1 | tail -z -n +"$max_backups" |
  sed -z 's/^[0-9]* //' | xargs -0 rm -v

这里的工作是由D3命令和各种下游管道完成的。下面是命令所做工作的详细说明:

F14H15

D6:它以秒为单位打印备份目录中所有D7文件的时代以来的文件名和文件年龄。为了能够用换行符(D8)处理文件名,我们需要用NULL (D9)结束每个条目。这就是输出的样子:$ tar.gz -printf '%Y‘*\0’\ tr '\n‘’1616867929 ./afile 5 tar.gz 1616868565 ./file 10 tar.gz 1616868560 ./file 1 tar.gz 1616868561 ./文件2 tar.gz 1616867927 ./文件3 tar.gz 1616867928 ./文件4 tar.gz 1616867930 ./文件6 tar.gz 1616868562 ./文件7 tar.gz 1616868563 ./文件8 tar.gz 1616868564 ./文件9 tar.gz

H210F211

在这个例子中,我将输出通过管道传送到D12,这样可以看得清楚,但是在实际输出中,每个记录的末尾都有一个D13

F114H115

D16:上面D17的输出通过管道传输到D18D18将按反向顺序(D20)对其进行数字排序,使用D21作为记录分隔符(D22),并且只考虑第一个字段(D23),这是文件的历史。输出结果如下:$ stat --printf '%Y %n\0‘"$backup_dir"/*tar.gz排序-rznk1,1’tr '\0‘'\n’n‘1616868565 ./file 10 tar.gz 1616868564 ./file 9 tar.gz 1616868563 ./file 8 tar.gz 1616868562 ./file 7 tar.gz 1616868561 ./file 2 tar.gz 1616868560 ./file 1 tar.gz 1616867930 ./file 6 tar.gz 1616867929 ./afile 5 tar。1616867928 ./文件4 tar.gz 1616867927 ./文件3 tar.gz

H224H125

D26:命令D27将打印从D28记录开始给它的最后一条记录。在这里,D29D30变量,这就是为什么需要将该变量设置为要保留的文件数加上一个。D31允许D32处理终止为空的记录。现在,我们有要删除的文件列表,但它们也有它们的年龄,我们需要删除它:$ stat -printf '%Y %n\0‘“$backup_dir/*tar.gz -rznk1,1 -rznk1,1 tail -z -n +5区tr '\0’'\n‘1616868561 ./文件2 tar.gz 1616868560 ./文件1 tar.gz 1616867930 ./文件6 tar.gz 1616867929 ./afile 5 tar.gz 1616867928 ./file 4 tar.gz 1616867927 ./file 3 tar.gz .

H233H134

D35:删除文件的年代,只留下名称。再一次,D36将处理终止为空的记录:$ stat --printf '%Y %n\0‘"$backup_dir"/*tar.gz /*tar.gz sort /*tar.gz sort -rznk1,1 -z -z -n +5 sed -z 's/^* //’AC.26 tr '\0‘\n’./file 2 tar.gz ./file 1 tar.gz ./file 6 tar.gz ./afile 5 tar.gz./file 4 tar.gz ./file 3 tar.gz

H237H138

D39:最后一步。这将删除文件,并且,再次,D40可以处理以空结尾的记录。

H241F242

重要的:脚本假定您使用的是GNU工具。C43声称是Linux并运行Debian,所以它应该适用于您,但我从未使用过该系统,所以我无法确定。

票数 1
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/642373

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档