S3 对象批量重命名快捷方法

本文所述操作适用于兼容 S3 协议的所有存储框架,包括 AWS S3Aliyun OSSMinIOCeph 等。


不知为何,截止目前,S3 协议并不包含对象重命名的接口。如果有重命名对象的需求,一般能想到的就是重新上传改名之后的对象,然后从存储桶中将原名对象删除。很明显,这种方式好比大炮打蚊子,目的达到了,累得一身汗,要是本地没有备份,还得先下载,费时费力费钱。特别是当待处理的对象的数量相当庞大的时候,如果不想持续加班一个月,那就要琢磨琢磨另辟蹊径才行。

能不能将存储桶挂载到本地,然后用本地 shell 命令操作其中的对象呢?值得一试!

挂载

使用 rclones3fs-fusegoofys 等工具挂载,这里以 goofys 为例。

  1. 直接下载编译好的执行文件wget https://github.com/kahing/goofys/releases/latest/download/goofys
  2. 设置执行权限chmod +x goofys
  3. S3 密钥配置
mkdir ~/.aws
vi ~/.aws/credentials

# 以下是 ~/.aws/credentials 内容
[default]
aws_access_key_id = xxxxxxx
aws_secret_access_key = yyyyyyyy
  1. 创建挂载点mkdir /mnt/foo
  2. 挂载
mkdir /opt/goofys
./goofys --endpoint https://us-east.s3.aws.com bucketName /mnt/foo/
  1. 验证是否挂载成功。
# 列出前 10 个文件
ls /mnt/foo/ | head -n 10
# 注意:该语句并不能减少 ls 的执行时间。当文件数量过多时,可以使用通配符减少 ls 的罗列数量。

重命名

挂载成功之后,我们就可以采用 mvrename 指令尝试重命名文件了,下面以 perl 版本的 rename 为例(该版本支持正则表达式)。

# 所有文件名只保留后 5 个字符,并更改扩展名
rename 's/\w*?(\w{5})\.mdi/$1.obj/' *
# 实际也是逐个文件处理,而非一次性同时处理,文件多则耗时
# 如果文件太多则会报 "Argument list too long"(虽然参数只有一个星号,但实则是将所有文件名查找出来后执行),可以改成如下方式:
find . -name "*" | xargs rename 's/\w*?(\w{5})\.mdi/$1.obj/'
# 虽然不会报错,但其实只是将查找文件名环节转给了 find,总耗时是一样的

为了更好更灵活地重命名巨量文件,只能编写脚本了。以下是示例代码:

rename_s3_objects()
{
local renamedCnt=0
for obj in ./*
do
        if [ `expr ${#obj} - 2` -gt 8 ]; then	# 如果不作判断,那么不管文件名是否符合,正则都会执行(耗时),然后再根据执行结果看是否重命名(重命名比正则更耗时)
                rename 's/\w*?(\w{5})\.mdi/$1.obj/' $obj
        fi	
	renamedCnt=$(($renamedCnt + 1))
	if [ `expr $renamedCnt % 100` -eq 0 ]; then
                # 每处理完 100 个对象就输出提示
		echo "$renamedCnt objects renamed"
	fi
done
return 0
}

rename_s3_objects

# 似乎 ``; $[]; $(()) 都可以执行运算

保存后,在命令行中使用 sh saved_file_name 执行即可。

经测算,在普通网络环境下,每重命名 100 个对象(大约 100M),耗时 70s 左右。并未检查过程中是否涉及到对象的传输(博主试验的服务器并没有带宽使用统计),推测应该是没有,有兴趣的朋友可以验证下。


除重命名外,类似于[批量]删除、S3 中对象加斜杠前缀(创建文件夹并移动文件)等指令应该也可以通过挂载方式玩转。

posted @ 2023-04-24 13:20  莱布尼茨  阅读(714)  评论(2编辑  收藏  举报