如何将 tar 压缩操作通过管道传输到 aws s3 cp?
How can I pipe a tar compression operation to aws s3 cp?
我正在 bash 中编写自定义备份脚本供个人使用。目标是通过 tar/gzip 压缩目录的内容,拆分压缩存档,然后将各部分上传到 AWS S3。
几个月前我第一次尝试编写这个脚本时,我能够通过类似的方式让它工作:
tar -czf - /mnt/STORAGE_0/dir_to_backup | split -b 100M -d -a 4 - /mnt/SCRATCH/backup.tgz.part
aws s3 sync /mnt/SCRATCH/ s3://backups/ --delete
rm /mnt/SCRATCH/*
这很适合我的目的,但需要 /mnt/SCRATCH
有足够的磁盘 space 来存储压缩目录。现在我想改进此脚本,使其不必依赖 /mnt/SCRATCH
中的足够 space,并进行了一些研究。我最终得到了类似的东西:
tar -czf - /mnt/STORAGE_0/dir_to_backup | split -b 100M -d -a 4 --filter "aws s3 cp - s3://backups/backup.tgz.part" -
这几乎可以工作,但是我的 S3 存储桶上的目标文件名不是动态的,而且它似乎只是在 运行 时多次覆盖 backup.tgz.part
文件。最终结果只是一个 100MB 的文件,而预期的几个 100MB 文件的结尾如 .part0001
.
任何指导将不胜感激。谢谢!
当使用 split
时,您可以使用环境变量 $FILE
来获取生成的文件名。
见 split man page:
--filter=COMMAND
write to shell COMMAND; file name is $FILE
对于您的用例,您可以使用如下内容:
--filter 'aws s3 cp - s3://backups/backup.tgz.part$FILE'
(需要单引号,否则会立即进行环境变量替换)
这将在 aws 上生成以下文件名:
backup.tgz.partx0000
backup.tgz.partx0001
backup.tgz.partx0002
...
完整示例:
tar -czf - /mnt/STORAGE_0/dir_to_backup | split -b 100M -d -a 4 --filter 'aws s3 cp - s3://backups/backup.tgz.part$FILE' -
您应该能够使用 GNU Parallel 轻松并行地完成它。它具有 --pipe
选项,可将输入数据拆分为大小 --block
的块,并将其分布在多个并行进程中。
因此,如果您想使用 100MB 块并并行使用 CPU 的所有内核,并将块号 ({#}
) 附加到 AWS 上文件名的末尾,您的命令看起来像这样:
tar czf - something | parallel --pipe --block 100M --recend '' aws s3 cp - s3://backups/backup.tgz.part{#}
您可以只使用 4 个 CPU 个内核,而不是 parallel -j4
个内核。
请注意,我将 "record end" 字符设置为空,这样它就不会试图避免拆分 mid-line,这是它的默认行为并且更好比 tarball 这样的二进制文件更适合文本文件处理。
我正在 bash 中编写自定义备份脚本供个人使用。目标是通过 tar/gzip 压缩目录的内容,拆分压缩存档,然后将各部分上传到 AWS S3。
几个月前我第一次尝试编写这个脚本时,我能够通过类似的方式让它工作:
tar -czf - /mnt/STORAGE_0/dir_to_backup | split -b 100M -d -a 4 - /mnt/SCRATCH/backup.tgz.part
aws s3 sync /mnt/SCRATCH/ s3://backups/ --delete
rm /mnt/SCRATCH/*
这很适合我的目的,但需要 /mnt/SCRATCH
有足够的磁盘 space 来存储压缩目录。现在我想改进此脚本,使其不必依赖 /mnt/SCRATCH
中的足够 space,并进行了一些研究。我最终得到了类似的东西:
tar -czf - /mnt/STORAGE_0/dir_to_backup | split -b 100M -d -a 4 --filter "aws s3 cp - s3://backups/backup.tgz.part" -
这几乎可以工作,但是我的 S3 存储桶上的目标文件名不是动态的,而且它似乎只是在 运行 时多次覆盖 backup.tgz.part
文件。最终结果只是一个 100MB 的文件,而预期的几个 100MB 文件的结尾如 .part0001
.
任何指导将不胜感激。谢谢!
当使用 split
时,您可以使用环境变量 $FILE
来获取生成的文件名。
见 split man page:
--filter=COMMAND
write to shell COMMAND; file name is $FILE
对于您的用例,您可以使用如下内容:
--filter 'aws s3 cp - s3://backups/backup.tgz.part$FILE'
(需要单引号,否则会立即进行环境变量替换)
这将在 aws 上生成以下文件名:
backup.tgz.partx0000
backup.tgz.partx0001
backup.tgz.partx0002
...
完整示例:
tar -czf - /mnt/STORAGE_0/dir_to_backup | split -b 100M -d -a 4 --filter 'aws s3 cp - s3://backups/backup.tgz.part$FILE' -
您应该能够使用 GNU Parallel 轻松并行地完成它。它具有 --pipe
选项,可将输入数据拆分为大小 --block
的块,并将其分布在多个并行进程中。
因此,如果您想使用 100MB 块并并行使用 CPU 的所有内核,并将块号 ({#}
) 附加到 AWS 上文件名的末尾,您的命令看起来像这样:
tar czf - something | parallel --pipe --block 100M --recend '' aws s3 cp - s3://backups/backup.tgz.part{#}
您可以只使用 4 个 CPU 个内核,而不是 parallel -j4
个内核。
请注意,我将 "record end" 字符设置为空,这样它就不会试图避免拆分 mid-line,这是它的默认行为并且更好比 tarball 这样的二进制文件更适合文本文件处理。