452

我通常这样做:

tar -czvf my_directory.tar.gz my_directory

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

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

我想:

my_file
my_file
my_file
4

20 回答 20

745

使用-Ctar 的开关:

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

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

确保你在做-C my_directory之前做.,否则你会得到当前目录中的文件。

于 2010-06-14T06:54:08.510 回答
261
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
于 2009-06-03T13:46:20.460 回答
67

您还可以像往常一样创建存档并使用以下命令提取它:

tar --strip-components 1 -xvf my_directory.tar.gz
于 2009-06-02T15:01:25.853 回答
41

TL;DR(没有./也没有./file1!)

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 的回答中),但这可能会导致“文件列表太长”错误。最好的方法是将它与 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(在 GNUfind中可用)告诉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 -
于 2016-09-16T11:30:06.160 回答
35

看看--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

于 2013-10-30T19:53:56.707 回答
21
cd my_directory
tar zcvf ../my_directory.tar.gz *
于 2009-06-02T14:53:38.223 回答
18

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

一种解决方案是使用一些 Bash glob 来列出所有文件,除了..这样的文件:

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

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

现在 tar 如果没有匹配的文件,将返回一个错误..?*or .[^.]*,但它仍然可以工作。如果错误是一个问题(您正在检查脚本是否成功),则此方法有效:

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
于 2012-03-19T19:22:17.253 回答
6
cd my_directory && tar -czvf ../my_directory.tar.gz $(ls -A) && cd ..

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

于 2017-02-09T17:19:47.300 回答
3

如果它是 Unix/Linux 系统,并且您关心隐藏文件(将被 * 忽略),您需要执行以下操作:

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

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

于 2009-06-02T16:38:22.467 回答
2

我会提出以下 Bash 函数(第一个参数是目录的路径,第二个参数是生成的存档的基本名称):

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在当前目录中生成存档。它适用于隐藏 (.*) 元素和文件名中带有空格的元素。

于 2014-02-27T10:46:45.633 回答
2

命令

创建标准存档文件。

find my_directory/ -maxdepth 1 -printf "%P\n" | tar -cvf my_archive.tar -C my_directory/ -T -

打包的文件和目录位于存档的根目录中,没有路径信息,更深的文件具有相对路径。
文件和目录前面没有奇怪的“./”。('./file')
没有特殊文件 '.' 被包含在内。

似乎需要另一个工具,如findor ls( ls -A -1) 来实现这些目标,并且tar仅使用其参数无法选择文件并创建具有此类要求的存档。

使用上述命令会创建一个归档 tar 文件,该文件可以进一步处理或交付给某人,而不会看起来很奇怪,也不需要解释或解包工具。

参数说明

-maxdepth 1
最多下降 1 级 - 无递归。在标准输出文件名上
-printf
打印格式
%P, 并在其下找到它的起始点的名称已被删除。
\n 换行符
printf 不在字符串末尾添加换行符。必须在此处添加

tar:
-C DIR,--directory=DIR
切换到目录 DIR

-T FILE,从管道中--files-from=FILE
获取名称以从 FILE 中提取或创建,
-
上面的 FILE 是标准输入


对其他解决方案的评论。

使用@aross 描述的解决方案可能会获得相同的结果。
这里与解决方案的区别在于哪个工具正在执行递归。如果您将作业留给find,则每个文件路径名称都会通过管道。它还发送所有目录名称,带有 --no-recursion 的 tar 忽略或添加为空目录,然后是每个目录中的所有文件。如果从 读取的文件中出现意外输出错误find,则 tar 不会知道或关心发生了什么。
但是通过进一步的检查,比如处理来自 find 的错误流,这可能是一个很好的解决方案,其中需要对文件进行许多选项和过滤器。
我更喜欢将递归保留在 tar 上,它看起来确实更简单,因此更稳定的解决方案。
以我复杂的目录结构,当 tar 不会报错时,我更有信心归档完整。

使用@serendrewpity 提出的另一种解决方案find似乎很好,但它在带有空格的文件名上失败。不同之处在于find$() 子 shell 提供的输出是按空间划分的。可以使用 printf 添加引号,但这会使语句更加复杂。

没有理由 cd 进入 my_directory 然后返回,同时使用 ../my_archive.tar 作为 tar 路径,因为 TAR 具有-C DIR,--directory=DIR命令,该命令仅用于此目的。

使用.(dot) 将包括点

使用 * 会让 shell 提供输入文件列表。可以使用 shell 选项来包含点文件。但这很复杂。该命令必须在允许的 shell 中执行。启用和禁用必须在 tar 命令之前和之后完成。如果未来存档的根目录包含太多文件,它将失败。

最后一点也适用于所有不使用管道的解决方案。

大多数解决方案都是在其中创建一个目录,其中包含文件和目录。这几乎是不可取的。

于 2020-12-19T14:06:18.127 回答
2
cd DIRECTORY
tar -czf NAME.tar.gz  *

星号将包括所有内容,甚至是隐藏的内容

于 2021-02-05T23:37:21.567 回答
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参数删除包含“.”的完整路径。还有所有 但是printf的格式字符串“%P”中的my_dir的文件和子目录列表中留下了残留物,并且可以通过find命令结果中的前导空格看到。

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

于 2020-05-16T22:19:53.947 回答
1
tar -czvf mydir.tgz -C my_dir/ `ls -A mydir`

在 mydir 上一层运行它。这不包括任何 [.] 或东西。

于 2021-02-17T16:49:59.307 回答
0

使用派克斯。

Pax 是一个已弃用的软件包,但它以一种简单的方式完美地完成了这项工作。

pax -w > mydir.tar mydir
于 2013-01-07T16:50:07.497 回答
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 命令添加一个或类似的过滤器以限制包含的文件。

于 2016-08-23T18:04:20.623 回答
0

我发现的最简单的方法:

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

于 2017-05-16T12:45:59.560 回答
0
function tar.create() {
        local folder="${1}"
        
        local tar="$(basename "${folder}")".tar.gz
        
        cd "${folder}" && tar -zcvf "../${tar}" .; cd - &> /dev/null
}

例子:

tar.create /path/to/folder

不客气。

于 2020-01-08T19:39:01.463 回答
-1
 tar -cvzf  tarlearn.tar.gz --remove-files mytemp/*

如果文件夹是 mytemp,那么如果您应用上述内容,它将压缩并删除文件夹中的所有文件,但不要管它

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

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

于 2013-02-13T21:37:00.250 回答
-5
tar -C my_dir -zcvf my_dir.tar.gz `ls my_dir`
于 2009-06-02T15:05:44.470 回答