GitLab CI/CD创建tar.gz排除自身,解决文件读取变更报错
解决tar打包时排除自身归档文件的问题
问题场景
在当前工作目录(例如/builds/project/)创建archive.tar.gz归档文件,需要确保该归档文件本身不会被打包进去。尝试使用--exclude=PATTERN选项但未成功,最终希望通过变量指定归档文件名并实现排除。
版本信息
$ bash --version GNU bash, version 5.2.15(1)-release (x86_64-pc-linux-gnu) Copyright (C) 2022 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software; you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. $ tar --version tar (GNU tar) 1.34 Copyright (C) 2021 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Written by John Gilmore and Jay Fenlason.
尝试过的无效命令及错误
# 选项顺序错误导致归档文件名识别失败 $ tar -czf --exclude=archive1.tar.gz archive1.tar.gz . || true tar: archive1.tar.gz: Cannot stat: No such file or directory tar: .: file changed as we read it tar: Exiting with failure status due to previous errors $ tar -czf --exclude="archive2.tar.gz" archive2.tar.gz . || true tar: archive2.tar.gz: Cannot stat: No such file or directory tar: .: file changed as we read it tar: Exiting with failure status due to previous errors $ tar -czf --exclude=./archive3.tar.gz archive3.tar.gz . || true tar: archive3.tar.gz: Cannot stat: No such file or directory tar (child): --exclude=./archive3.tar.gz: Cannot open: No such file or directory tar (child): Error is not recoverable: exiting now tar: --exclude=./archive3.tar.gz: Cannot write: Broken pipe tar: Child returned status 2 tar: Error is not recoverable: exiting now # 选项顺序正确但相对路径排除失效 $ tar -czf archive5.tar.gz --exclude=archive5.tar.gz . || true tar: .: file changed as we read it $ TAR_FILE=archive13.tar.gz ; tar -czf $TAR_FILE --exclude=$TAR_FILE . || true tar: .: file changed as we read it
有效解决方案
方法1:使用绝对路径排除
用绝对路径精准匹配要排除的归档文件,避免相对路径的匹配歧义:
TAR_FILE="archive.tar.gz" tar -czf "$TAR_FILE" --exclude="$(pwd)/$TAR_FILE" .
原理:tar遍历当前目录时,文件路径以相对形式存在,而$(pwd)/$TAR_FILE是归档文件的绝对路径,能准确匹配到正在创建的文件,从而实现排除。
方法2:提前创建空归档文件再排除
先创建空的归档文件,让tar在遍历目录时能识别到该文件并排除:
TAR_FILE="archive.tar.gz" touch "$TAR_FILE" tar -czf "$TAR_FILE" --exclude="$TAR_FILE" .
原理:提前创建文件后,tar遍历目录时会找到该文件并应用排除规则,后续tar写入归档内容时不会将自身打包进去。
方法3:将归档文件放在当前目录外
直接把归档文件创建到当前目录的上级目录,从根源避免需要排除的问题:
TAR_FILE="../archive.tar.gz" tar -czf "$TAR_FILE" .
失败原因分析
- 选项顺序错误:前几个命令将
--exclude放在-czf之后紧跟,而-f选项要求后面必须直接跟归档文件名,导致tar误将--exclude=...当作归档文件名,引发报错。 - 相对路径匹配问题:当使用相对路径排除时,tar在创建归档文件的过程中,文件处于动态生成状态,tar遍历到当前目录时,归档文件可能还未完全生成,或者相对路径的匹配逻辑无法识别正在写入的文件,导致排除规则失效。
内容的提问来源于stack exchange,提问作者rosaLux161
相关产品推荐
相关产品推荐

