如何在不包含目录本身的情况下tar文件和文件夹目录?

时间:2009-06-02 14:48:04

标签: gzip archive tar gz

我通常会这样做:

tar -czvf my_directory.tar.gz my_directory

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

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

我想:

my_file
my_file
my_file

20 个答案:

答案 0 :(得分:590)

使用tar的-C开关:

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

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

确保在执行-C my_directory之前执行.,否则您将获得当前目录中的文件。

答案 1 :(得分:207)

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 :(得分:50)

您也可以照常创建档案并使用以下内容解压缩:

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

答案 3 :(得分:31)

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

答案 4 :(得分:21)

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命令(它使用-T -从STDIN获取文件名)。需要-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 -

答案 5 :(得分:16)

This Answer应该适用于大多数情况。但请注意文件名如何存储在tar文件中,例如./file1而不仅仅是file1。我发现这在使用此方法操作BuildRoot中用作包文件的tarball时会出现问题。

一种解决方案是使用一些Bash globs列出除..之外的所有文件,如下所示:

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

这是我从this answer学到的一个技巧。

如果没有匹配..?*.[^.]*的文件,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 globs *,因此,使用:

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

答案 6 :(得分:15)

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

答案 7 :(得分:3)

如果是Unix / Linux系统,并且您关心隐藏文件(*会遗漏*),您需要这样做:

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

我不知道Windows下隐藏文件的样子。

答案 8 :(得分: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。它适用于隐藏(。*)元素以及文件名中包含空格的元素。

答案 9 :(得分:1)

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

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

答案 10 :(得分: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 ')

在第一个命令中, 查找 返回文件列表和 my_dir 的子目录。 但是,目录 my_dir 本身作为“。”包含在该列表中。 -printf 参数将删除包含“。”的完整路径。以及所有 但是, printf 的格式字符串 '%P' 中的会在 my_dir 的文件和子目录列表,并且在 find 的结果中可以在前导空格处看到>命令。

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

答案 11 :(得分:0)

使用pax。

Pax是一个已弃用的软件包,但它可以完美地完成工作。

pax -w > mydir.tar mydir

答案 12 :(得分: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=-
}

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

答案 13 :(得分:0)

我发现最简单的方法:

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

答案 14 :(得分: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

不客气。

答案 15 :(得分:0)

命令

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

这会创建一个标准的存档文件。标准的方式是您要打包的文件和目录位于存档的根目录中。没有像“.”这样的额外特殊文件和目录为 ./ 在每个 './file' 之前。
尝试了这么多已经在这里只有一个成功的解决方案,在我看来,在管道的左侧使用 find 或其他可能的命令,例如 ls -A -1(-1 作为“一个”,而不是 - l as 'L') 是实现上述目标的唯一途径。

如果 tar 文件被进一步处理,或者作为我工作的产品交付给某人,那么我不想在那里有一些奇怪的东西。

参数说明

-maxdepth 1
最多下降 1 个级别 - 无递归。
-printf
在标准输出上打印格式
%P 文件名以及删除它所在的起始点的名称。
\n 换行符
printf 不会在字符串末尾添加换行符。这里一定要加

焦油:
-C DIR--directory=DIR
切换到目录 DIR

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


对其他解决方案的评论。

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

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

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

使用 .(点)将包含点

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

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

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

答案 16 :(得分:0)

cd DIRECTORY
tar -czf NAME.tar.gz  *

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

答案 17 :(得分:0)

tar -czvf mydir.tgz -C my_dir/ `ls -A mydir`

在 mydir 的上一级运行它。 这不会包括任何 [.] 或其他内容。

答案 18 :(得分:-1)

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

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

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

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

答案 19 :(得分:-3)

tar -C my_dir -zcvf my_dir.tar.gz `ls my_dir`