如何压缩文件和文件夹的目录而不包含目录本身?


382

我通常会这样做:

tar -czvf my_directory.tar.gz my_directory

如果我只想在my_directory中包括所有内容(包括任何隐藏的系统文件),而不包括目录本身,该怎么办?我不要

my_directory
   --- my_file
   --- my_file
   --- my_file

我想要:

my_file
my_file
my_file

这是默认的行为tar -czf吗?就我而言,它仅存储文件,而不存储目录。当我只是tar目录时,它包括它,但tar -czf仅添加文件。
杜尔加·斯瓦鲁普

Answers:


233
cd my_directory/ && tar -zcvf ../my_dir.tgz . && cd - 

应该一行完成这项工作。它也适用于隐藏文件。至少在bash中,“ *”不会通过路径名扩展来扩展隐藏文件。以下是我的实验:

$ mkdir my_directory
$ touch my_directory/file1
$ touch my_directory/file2
$ touch my_directory/.hiddenfile1
$ touch my_directory/.hiddenfile2
$ cd my_directory/ && tar -zcvf ../my_dir.tgz . && cd ..
./
./file1
./file2
./.hiddenfile1
./.hiddenfile2
$ tar ztf my_dir.tgz
./
./file1
./file2
./.hiddenfile1
./.hiddenfile2

2
这也适用于带有空格或其他特殊字符的文件。做得好!
PanCrit

29
不完美-tar文件包含“。” 还有./file1而不只是file1。我喜欢下面的mateusza解决方案,在取消涂标时使用--strip-components。
伊万

23
@Ivan如果替换.*,则该命令将按cd my_directory/ && tar -zcvf ../my_dir.tgz * && cd ..预期运行。
匿名

3
@jmathew您还可以使用子外壳程序,以使当前外壳程序的工作目录不变:$ (cd my_directory/ && tar -zcvf ../my_dir.tgz .)
Alec

我知道这是一个老答案,但是cd进入目录却很la脚。至少可以使用pushdpopd如果tar没有类似的标志-C
安德里斯

667

使用-Ctar 的开关:

tar -czvf my_directory.tar.gz -C my_directory .

-C my_directory告诉tar改变当前目录my_directory,然后.表示“添加整个当前目录”(包括隐藏文件和子目录)。

确保-C my_directory先执行操作.,否则将获得当前目录中的文件。


5
+1谢谢!那是该死的'。我不见了。如此加重
JCotton

14
“与大多数选项不同,-C在它出现在要处理的文件列表中时进行处理。请考虑以下命令: tar --create --file=foo.tar -C /etc passwd hosts -C /lib libc.aapl.jhu.edu/Misc/Unix-info/tar/tar_65.html 我总是尝试tar -czvf my_directory.tar.gz * -C my_directory并那行不通。-C位置很重要!该死的焦油...
m-ric

57
不完美-tar文件包含“。” 还有./file1而不只是file1。我喜欢下面的mateusza解决方案,在取消涂标时使用--strip-components。
伊万

3
@Superole:shell在运行tar之前替换了通配符。另请注意,使用类似通配符的操作*将不包括隐藏文件(这是原始要求)。
dubek 2013年

28
它创建 。作为.tar.gz中的根目录。
匿名

59

您还可以照常创建存档,并使用以下命令将其提取:

tar --strip-components 1 -xvf my_directory.tar.gz

3
此解决方案在您处理尚未了解所有要求的情况下创建的tarball的情况下特别有用……
Digger

2
注意,这--strip-components是GNU扩展。
zneak

2
通过提供上下文中的“照常”示例可以改善此答案。
乔什·哈布达斯

33

看一下--transform/ --xform,当文件添加到归档文件时,它使您有机会调整文件名:

% mkdir my_directory
% touch my_directory/file1
% touch my_directory/file2
% touch my_directory/.hiddenfile1
% touch my_directory/.hiddenfile2
% tar -v -c -f my_dir.tgz --xform='s,my_directory/,,' $(find my_directory -type f)
my_directory/file2
my_directory/.hiddenfile1
my_directory/.hiddenfile2
my_directory/file1
% tar -t -f my_dir.tgz 
file2
.hiddenfile1
.hiddenfile2
file1

转换表达式类似于的表达式sed,我们可以使用除/,在上面的示例中)以外的分隔符。
https://www.gnu.org/software/tar/manual/html_section/tar_52.html


3
我会做的。其他什么都只是黑客!
jwg

2
这是一个更好的解决方案。
leesei

这是最好的解决方案。
justhalf

1
好的解决方案,但这可能会导致file list too long我的解决方案防止了这种情况,并且更加灵活。
2011年

这是一个很好的解决方案。您也可以--xform多次传递多个路径。
资格

26

TL; DR

find /my/dir/ -printf "%P\n" | tar -czf mydir.tgz --no-recursion -C /my/dir/ -T -

在某些情况下(仅归档文件,目录和符号链接):

find /my/dir/ -printf "%P\n" -type f -o -type l -o -type d | tar -czf mydir.tgz --no-recursion -C /my/dir/ -T -

说明

不幸的是,以下内容./在归档文件中包含一个父目录:

tar -czf mydir.tgz -C /my/dir .

您可以使用--transform配置选项将所有文件移出该目录,但这不会摆脱.目录本身。驯服命令变得越来越困难。

您可以用来$(find ...)向命令中添加文件列表(如magnus的answer),但这可能会导致“文件列表过长”错误。最好的方法是将其与tar的-T选项结合使用,如下所示:

find /my/dir/ -printf "%P\n" -type f -o -type l -o -type d | tar -czf mydir.tgz --no-recursion -C /my/dir/ -T -

基本上,它的工作是列出目录下的所有文件(-type f),链接(-type l)和子目录(-type d),使用来使所有文件名相对-printf "%P\n",然后将其传递给tar命令(它使用来从STDIN中获取文件名-T -)。该-C选项是必需的,因此tar知道具有相对名称的文件位于何处。该--no-recursion标志是为了使tar不会递归到被告知要存档的文件夹中(导致重复文件)。

如果您需要对文件名做一些特殊的事情(过滤,跟随符号链接等),该find命令功能非常强大,您只需删除tar上面命令的一部分即可对其进行测试:

$ find /my/dir/ -printf "%P\n" -type f -o -type l -o -type d
> textfile.txt
> documentation.pdf
> subfolder2
> subfolder
> subfolder/.gitignore

例如,如果要过滤PDF文件,请添加 ! -name '*.pdf'

$ find /my/dir/ -printf "%P\n" -type f ! -name '*.pdf' -o -type l -o -type d
> textfile.txt
> subfolder2
> subfolder
> subfolder/.gitignore

非GNU查找

该命令使用printf(在GNU中可用find)告诉find打印其结果的相对路径。但是,如果您没有GNU find,这可以使路径相对(用删除父母sed):

find /my/dir/ -type f -o -type l -o -type d | sed s,^/my/dir/,, | tar -czf mydir.tgz --no-recursion -C /my/dir/ -T -

2
好答案。非常详尽,最重要的是,可以完美地解决问题。
亚历克斯

16

该答案在大多数情况下都应该有效。但是请注意,文件名如何存储在tar文件中,例如,./file1而不是file1。我发现使用此方法来处理BuildRoot中用作包文件的tarball时,这会引起问题。

一种解决方案是使用一些Bash Glob列出所有文件,但..如下所示:

tar -C my_dir -zcvf my_dir.tar.gz .[^.]* ..?* *

这是我从这个答案中学到的技巧。

现在,如果没有与..?*或匹配的文件.[^.]*,则tar将返回错误,但仍然可以使用。如果错误是一个问题(您正在检查脚本中是否成功),则可以这样做:

shopt -s nullglob
tar -C my_dir -zcvf my_dir.tar.gz .[^.]* ..?* *
shopt -u nullglob

尽管现在我们弄乱了shell选项,但我们可能会认为拥有*匹配的隐藏文件更加巧妙:

shopt -s dotglob
tar -C my_dir -zcvf my_dir.tar.gz *
shopt -u dotglob

这可能无法*在当前目录中的Shell Glob处起作用,因此,请使用:

shopt -s dotglob
cd my_dir
tar -zcvf ../my_dir.tar.gz *
cd ..
shopt -u dotglob

1
执行tar: start.sh: Cannot stat: No such file or directory此操作时会遇到奇怪的错误,这会发生在当前目录中的所有文件中!如何避免这种情况?
BrainStone 2013年

@BrainStone我得到完全相同的结果。
mbmast

15
cd my_directory
tar zcvf ../my_directory.tar.gz *

2
Hal明确询问隐藏文件。您还需要。?? *。
PanCrit

2
-1:这不会将隐藏文件添加到tar中。请参阅tbman的答案。
dubek 2010年

3

如果它是Unix / Linux系统,并且您关心隐藏的文件(*会丢失),则需要执行以下操作:

cd my_directory
tar zcvf ../my_directory.tar.gz * .??*

我不知道Windows下隐藏的文件是什么样的。


2

我建议使用以下Bash函数(第一个参数是dir的路径,第二个参数是结果存档的基本名称):

function tar_dir_contents ()
{
    local DIRPATH="$1"
    local TARARCH="$2.tar.gz"
    local ORGIFS="$IFS"
    IFS=$'\n'
    tar -C "$DIRPATH" -czf "$TARARCH" $( ls -a "$DIRPATH" | grep -v '\(^\.$\)\|\(^\.\.$\)' )
    IFS="$ORGIFS"
}

您可以通过以下方式运行它:

$ tar_dir_contents /path/to/some/dir my_archive

它将my_archive.tar.gz在当前目录中生成存档。它适用于隐藏(。*)元素以及文件名中带有空格的元素。


2
cd my_directory && tar -czvf ../my_directory.tar.gz $(ls -A) && cd ..

这对我有用,它包含所有隐藏文件,而没有将所有文件放在名为“”的根目录中。就像在tomoe的答案中一样


1
tar.create() {
        local folder="${1}"

        local tar="$(basename "${folder}")".tar.gz

        cd "${folder}" && tar -zcvf "../${tar}" .; cd - &> /dev/null
}

例:

tar.create folder

别客气。


1

这对我有用。

tar -cvf my_dir.tar.gz -C /my_dir/ $(find /my_dir/ -maxdepth 1 -printf '%P ')

您也可以使用

tar -cvf my_dir.tar.gz -C /my_dir/ $(find /my_dir/ -mindepth 1 -maxdepth 1 -printf '%P ')

在第一个命令中,find返回my_dir的文件和子目录的列表。但是,目录my_dir本身作为“。”包含在该列表中。该-printf参数删除的完整路径,包括“” 还有所有 但是,那 格式字符串“%P”printf的叶子中的文件和子目录的列表残余MY_DIR并且可以通过结果的前导空格可以看出查找命令。

对于TAR来说这不是问题,但是如果要解决此问题,请在第二个命令中添加-mindepth 1


0

使用pax。

Pax是已弃用的软件包,但可以完美且简单地完成工作。

pax -w > mydir.tar mydir

最实用
且能

此命令将创建内容为mydir.tar的内容:mydir / file1 mydir / file2,正是要避免的内容。
亚历克斯

0

我发现的最简单方法:

cd my_dir && tar -czvf ../my_dir.tar.gz *


1
那将不包括隐藏文件。
异步

0
# tar all files within and deeper in a given directory
# with no prefixes ( neither <directory>/ nor ./ )
# parameters: <source directory> <target archive file>
function tar_all_in_dir {
    { cd "$1" && find -type f -print0; } \
    | cut --zero-terminated --characters=3- \
    | tar --create --file="$2" --directory="$1" --null --files-from=-
}

安全处理带空格或其他异常字符的文件名。您可以选择-name '*.sql'向find命令添加一个或类似的过滤器以限制包含的文件。


-1
 tar -cvzf  tarlearn.tar.gz --remove-files mytemp/*

如果该文件夹是mytemp,则如果应用上述内容,它将压缩并删除该文件夹中的所有文件,但请不要理会它

 tar -cvzf  tarlearn.tar.gz --remove-files --exclude='*12_2008*' --no-recursion mytemp/*

您可以指定排除模式,也可以指定不查看子文件夹


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.