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

我通常这样做:

tar -czvf my_directory.tar.gz my_directory

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

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

我想要:

my_file
my_file
my_file
616726 次浏览
cd my_directory
tar zcvf ../my_directory.tar.gz *

你也可以像往常一样创建存档并提取它:

tar --strip-components 1 -xvf my_directory.tar.gz
tar -C my_dir -zcvf my_dir.tar.gz `ls my_dir`

如果它是Unix/Linux系统,并且你关心隐藏文件(会被*漏掉),你需要做:

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

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

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

使用tar的-C开关:

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

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

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

警告:你将得到的条目是./file-name.ext而不是file-name.ext!

如果你需要file-name.ext形式的条目,请阅读其他答案。

这个答案应该在大多数情况下工作。但是请注意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 globs *,所以,或者,使用:

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

使用pax。

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

pax -w > mydir.tar mydir
 tar -cvzf  tarlearn.tar.gz --remove-files mytemp/*

如果文件夹是mytemp,那么如果你应用上面的方法,它会压缩并删除文件夹中的所有文件,但不要管它

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

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

看一下--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 < / p >

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

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。它适用于隐藏(.*)元素和文件名中有空格的元素。

# 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'或类似的过滤器来限制包含的文件。

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

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

在某些条件下(只归档文件,dirs和符号链接):

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 ...)向命令中添加一个文件列表(就像在马格努斯的回答中一样),但这可能会导致“文件列表太长”。错误。最好的方法是将它与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

Non-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 -
cd my_directory && tar -czvf ../my_directory.tar.gz $(ls -A) && cd ..

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

我发现最简单的方法是:

CD my_dir &&Tar -czvf ./my_dir.tar.gz *

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

不客气

这对我来说很有效。

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 ')
在第一个命令中,< em >找到< / em >返回< em > my_dir < / em >的文件和子目录的列表。 然而,目录< em > my_dir < / em >本身包含在该列表中为'。' < em > printf < / em >参数删除完整路径,包括'。'和所有 然而,< em > printf < / em >的格式字符串< em > ' % P”< / em >中的< em > my_dir < / em >的文件和子目录列表中留下了剩余,可以通过< em >找到< / em >命令的结果中的前导空格看到。< / p >

这对TAR来说不是问题,但如果你想修复这个问题,可以在第二个命令中添加< em > -mindepth 1 < / em >

命令

创建标准归档文件。

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

压缩文件和dirs文件在存档的根目录下,没有路径信息,较深的文件有相对路径。
没有奇怪的样子。”/'放在文件和dirs前面。(“。/文件”)
没有特殊文件。

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

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

参数描述

< p > -maxdepth 1
最多下降1级-无递归。
-printf
在标准输出
上打印格式 %P文件的名称,删除它所在的起始点的名称。
\n换行
Printf不会在字符串的末尾添加换行符。它必须添加在这里

< p >沥青:
-C DIR--directory=DIR
更改目录DIR

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


对其他解决方案的评论。

使用@ cross描述的解决方案也可以实现相同的结果。
这里的解决方案的不同之处在于使用哪种工具进行递归。如果将作业留给find,则每个文件路径名称都将通过管道。它还发送所有目录名,tar使用——no-递归函数忽略或将其添加为空,后跟每个目录中的所有文件。如果在从find读取的文件中出现意外输出错误,tar将不知道或不关心发生了什么。
但是通过进一步的检查,比如从find处理错误流,对于需要对文件进行许多选项和过滤器的情况,这可能是一个很好的解决方案。
我更喜欢把递归留在tar上,它似乎更简单,更稳定的解决方案。
对于我复杂的目录结构,当tar不会报告错误时,我更有信心存档是完整的

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

当使用../my_archive.tar作为tar路径时,没有理由cd到my_directory然后返回,因为tar有-C DIR--directory=DIR命令,这就是为了这个目的而存在的。

使用. (dot)将包含圆点

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

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

大多数解决方案是创建一个目录,里面是文件和dirs。这几乎是人们所不希望看到的。

cd DIRECTORY
tar -czf NAME.tar.gz  *

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

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

运行它比mydir高一级。 这将不包括任何[。

.

tar存档:

# tar -czvf mydir.tar.gz mydir

解压存档:

# tar -xf mydir.tar.gz

如果使用bash,这应该是最简单的正确答案

cd my_directory
shopt -s dotglob
tar -czvf ../my_directory.tar.gz *
shopt -u dotglob

(从https://stackoverflow.com/a/9776491/7726468)

测试这个解决方案: enter image description here < / p >