tar:文件在我们读取时已更改


76

我正在使用maketar备份。执行makefile时,tar命令显示file changed as we read it。在这种情况下,

  • 警告出现时tar包还可以
  • 但它会停止tar命令以进行以下备份
  • 显示警告的文件实际上并没有改变-出现警告真的很奇怪
  • 显示警告的文件是随机出现的,我的意思是,每次我运行makefile时,显示警告的文件都是不同的
  • --ignore-failed-read没有帮助。我在MinGW中使用tar 1.23
  • 我只是将计算机更改为WIN7 64位。该脚本在旧的WIN7 32位上运行良好。但是tar版本并不像1.23那样新。

如何停止tar的警告,以在警告之后停止备份?


编辑2:这可能是原因

正如我上面所说,bash shell脚本在我的旧计算机上运行良好。与旧计算机相比,msys版本有所不同。tar命令的版本也是如此。在旧计算机中,tar是1.13.19,在新计算机中是1.23。我复制了旧的tar命令,而没有将其依赖项msys-1.0.dll复制到新计算机上,并将其重命名为tar_old。我还更新了shell脚本中的tar命令并运行了该脚本。那一切都很好。因此,问题似乎出在tar命令上。我确定去皮时没有任何文件更改。新版本中的tar命令有问题吗?我不知道。


编辑1:添加更多详细信息

备份由bash shell脚本调用。它扫描目标目录并生成makefile,然后调用make以使用tar命令进行备份。接下来是bash shell脚本构建的典型makefile。

#--------------------------------------------
# backup VC
#--------------------------------------------
# the program for packing
PACK_TOOL=tar

# the option for packing tool
PACK_OPTION=cjvf

# M$: C driver
WIN_C_DIR=c:

# M$: D driver
WIN_D_DIR=d:

# M$: where the software is
WIN_PRG_DIR=wuyu/tools
# WIN_PRG_DIR=

# where to save the backup files
BAKDIR=/home/Wu.Y/MS_bak_MSYS

VC_FRAMEWORK=/home/Wu.Y/MS_bak_MSYS/tools/VC/VC_framework.tar.bz2
VC_2010=/home/Wu.Y/MS_bak_MSYS/tools/VC/VC_2010.tar.bz2

.PHONY: all

all: $(VC_FRAMEWORK) $(VC_2010)

$(VC_FRAMEWORK): $(WIN_C_DIR)/$(WIN_PRG_DIR)/VC/Framework/*
    @$(PACK_TOOL) $(PACK_OPTION) "$@" --ignore-failed-read /c/$(WIN_PRG_DIR)/VC/Framework
$(VC_2010): $(WIN_C_DIR)/$(WIN_PRG_DIR)/VC/VS2010/*
    @$(PACK_TOOL) $(PACK_OPTION) "$@" --ignore-failed-read /c/$(WIN_PRG_DIR)/VC/VS2010

如您所见,tar包存储在〜/ MS_bak_MSYS / tools / VC / VC_2010.tar.bz2中。我在〜/ qqaa中运行脚本。~/MS_bak_MSYS从tar命令中排除。因此,我正在创建的tar文件不在我尝试放入tar文件的目录内。这就是为什么我对发出警告感到奇怪。


您似乎正在使用Windows安装程序,因此与您无关。但是,当基础文件系统是glusterfs时,我们也会遇到类似的问题。当lstat和fstat返回不同的值时,似乎有一个错误:bugzilla.redhat.com/show_bug.cgi?
id=1058526

在Windows docker挂载的卷上使用tar遇到了此问题。交换tar实用程序pax为我工作。
安德里亚斯(Andreas)

Answers:


76

我还遇到了tar消息“阅读过程中发生了变化”。对我来说,这些消息是在bitbake构建环境中制作Linux文件系统的tar文件时发生的。此错误是零星的。

对我来说,这不是由于从同一目录创建tar文件。我假设在tar文件创建过程中实际上有一些文件被覆盖或更改。

该消息是警告,仍然会创建tar文件。我们仍然可以通过设置选项禁止显示这些警告消息

--warning=no-file-changed

http://www.gnu.org/software/tar/manual/html_section/warnings.html

在警告消息中,tar返回的退出代码仍为“ 1”:http : //www.gnu.org/software/tar/manual/html_section/Synopsis.html

因此,如果我们从脚本中的某些函数调用tar文件,则可以处理如下退出代码:

set +e 
tar -czf sample.tar.gz dir1 dir2
exitcode=$?

if [ "$exitcode" != "1" ] && [ "$exitcode" != "0" ]; then
    exit $exitcode
fi
set -e

我有同样的问题,这个答案通过赋予我解决问题的能力来“解决”我的问题。谢谢@sandeep。
jaskho 2014年

11
带有1以下内容的Tar扩展:“如果为tar提供了--create 、、 append或update选项,则此退出代码表示某些文件在存档时已更改,因此生成的存档中不包含确切的文件集的副本。” 这真是令人jaw目结舌的不良行为-它将杀死管道,并且无法阻止它。facepalm
Otheus

注意@Otheusset +e
Ryan Brodie

2
@RyanBrodie我一直在思考set -o pipefail; tar ... | gzip。但是我收回了;它不会杀死整个管道,因为退出被推迟到执行结束。
Otheus

59

虽然已经很晚了,但是最近我也遇到了同样的问题。

问题是因为dir.的更改与xyz.tar.gz运行命令后创建的一样。有两种解决方案:

解决方案1: tar不介意是否在中的任何目录中创建了归档文件.。可能由于某些原因无法在工作空间之外创建档案。通过创建一个临时目录来解决该问题,以将归档文件放置为:

mkdir artefacts
tar -zcvf artefacts/archive.tar.gz --exclude=./artefacts .
echo $?
0

解决方案2: 我喜欢这个。在运行tar之前创建存档文件:

touch archive.tar.gz
tar --exclude=archive.tar.gz -zcvf archive.tar.gz .
echo $?
0

6
在解决方案2中,只需--exclude=archive.tar.gz在其他优化之前放置-zvcf,实际上效果很好。
Kaj Kandler's

36

如果要帮助调试此类问题,则需要提供make规则或至少提供您调用的tar命令。如果没有要查看的命令,我们如何查看该命令出了什么问题?

但是,在99%的时间中,出现这样的错误意味着您正在尝试将其放入tar文件的目录中创建tar文件。因此,当tar尝试读取目录时,它会找到tar文件作为目录的成员,开始读取它并将其写到tar文件中,从开始读取tar文件到完成之间读取tar文件,说明tar文件已更改。

因此,例如:

tar cf ./foo.tar .

没有办法“阻止”此操作,因为它没有错。在创建tar文件时,只需将其放在其他位置,或者找到另一种方式(使用--exclude或其他方法)来忽略tar文件。


我在原始帖子中添加了更多详细信息。请检查。
warem 2013年

根据此处的信息,我不知道出了什么问题。但是,我对使用Windows或cygwin知之甚少...我确实知道Windows文件系统与WRT多个程序访问同一文件相比,比基于POSIX的文件系统困难得多。但这似乎与您的情况并不直接相关。我只能建议@您删除规则中的,并检查make正在打印的命令以确保其正确无误,然后查看tar试图创建的文件(从v选项输出)以确保没有任何神秘之处。
MadScientist 2013年


5

加强Fabian的一线制;让我们说,我们只想忽略退出状态1,但如果有其他情况,则保留退出状态:

tar -czf sample.tar.gz dir1 dir2 || ( export ret=$?; [[ $ret -eq 1 ]] || exit "$ret" )

这一步完成了sandeep脚本的所有工作。



0

它通过添加20秒的简单睡眠超时为我工作。如果您的源目录仍在写入,则可能会发生这种情况。因此,请进行睡眠以使备份完成,然后tar应该可以正常工作。这也帮助我获得了正确的退出状态。

sleep 20
tar -czf ${DB}.${DATE}.tgz ./${DB}.${DATE}

0

我不确定它是否适合您,但我注意到tar在管道模式下更改/删除的文件不会失败。明白了吗。

测试脚本:

#!/usr/bin/env bash
set -ex
tar cpf - ./files | aws s3 cp - s3://my-bucket/files.tar
echo $?

手动删除随机文件...

输出:

+ aws s3 cp - s3://my-bucket/files.tar
+ tar cpf - ./files
tar: ./files/default_images: File removed before we read it
tar: ./files: file changed as we read it
+ echo 0
0

1
这是因为默认情况下,管道内部会忽略退出代码。最好通过“ set -o pipefail”将其恢复。
谢尔盖
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.