如何使“tar --exclude”在* nix环境中表现一致?

时间:2015-10-12 08:03:50

标签: linux macos bash

我正在编写一个bash脚本来进行部署tarball,脚本必须在OSX和Linux上运行。

我有一个如下所示的目录结构,在bash脚本中我需要tar除./foo之外的内容,但包括./baz/foo

$ find .
.
./bar
./baz
./baz/foo
./foo

简单!通常我会通过将--exclude='./foo'传递给tar命令来执行此操作,但我发现--exclude=pattern的行为在OSX和CentOS中是不同的。

我的问题是,如何最好地克服这个问题?如何使两个环境的行为相同或至少检测到所需的更改?

或者,任何人都可以为他们确认这种行为(OSX 10.11),以便我知道我没有一些奇怪的环境吗?

CentOS按预期工作:

$ tar zcfv ../test.tar.gz --exclude='./foo' .
./
./bar/
./baz/
./baz/foo/

OSX表现不同:

$ tar zcfv ../test.tar.gz --exclude='./foo' .
a .
a ./bar
a ./baz

经过几个小时的阅读文档,我发现没有什么可以解释这种不同的行为,但通过反复试验,我发现使用插入符表示模式的开始在OSX上有效。

OSX的修复程序(使用插入符号):

$ tar zcfv ../test.tar.gz --exclude='^./foo' .
a .
a ./bar
a ./baz
a ./baz/foo

但是在CentOS上不起作用:

$ tar zcfv ../test.tar.gz --exclude='^./foo' .
./
./bar/
./foo/
./baz/
./baz/foo/

最后,我注意到OSX附带了bsdtar而不是GNU tar,所以这是问题的根源吗?

OSX:

$ tar --version
bsdtar 2.8.3 - libarchive 2.8.3

CentOS的:

$ tar --version
tar (GNU tar) 1.23

1 个答案:

答案 0 :(得分:1)

感谢您的评论。在--exclude=pattern的实现中,这似乎是bsdtar和GNU tar之间的根本区别,并且没有办法让它们表现相同。

由于我可以控制操作系统环境,我可接受的解决方法是使用brew在OSX上安装GNU tar(感谢@Seer)。然后我在我的脚本中使用以下内容来检测安装的tar是否为GNU,如果没有则回退到gtar。如果没有安装gtar,它将中止。

# OSX uses bsdtar which causes problems with --exclude=pattern
# so force use of gtar if non-GNU tar detected
tar --version | grep -q 'gnu'
if [ $? -eq 0 ]
then
    echo "Detected GNU tar - using tar"
    TAR_BIN=`command -v tar 2>&1` || { echo >&2 "I require tar but it is not installed. Aborting."; exit 1; }
else
    echo "Detected non-GNU tar - using gtar"
    TAR_BIN=`command -v gtar 2>&1` || { echo >&2 "I require gtar but it is not installed. Aborting."; exit 1; }
fi

# this will now work consistently as GNU tar is always used
$TAR_BIN zcfv ../test.tar.gz --exclude='./foo' .

注意:CentOS至少实际上是别名gtar到tar,所以假设使用gtar命令可能是安全的,但我更喜欢上面的方法。