如何在不包含目录本身的情况下压缩文件和文件夹的目录?
我通常会这样做:
tar -czvf my_directory.tar.gz my_directory
如果我只想包含 my_directory 中的所有内容(包括任何隐藏的系统文件),而不是目录本身,该怎么办? 我不想要:
my_directory
--- my_file
--- my_file
--- my_file
我想要:
my_file
my_file
my_file
I typically do:
tar -czvf my_directory.tar.gz my_directory
What if I just want to include everything (including any hidden system files) in my_directory, but not the directory itself? I don't want:
my_directory
--- my_file
--- my_file
--- my_file
I want:
my_file
my_file
my_file
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(22)
使用帕克斯。
Pax 是一个已弃用的软件包,但它以简单的方式完美地完成了工作。
Use pax.
Pax is a deprecated package but does the job perfectly and in a simple fashion.
安全地处理带有空格或其他不常见字符的文件名。 您可以选择向 find 命令添加
-name '*.sql'
或类似的过滤器来限制包含的文件。Safely handles filenames with spaces or other unusual characters. You can optionally add a
-name '*.sql'
or similar filter to the find command to limit the files included.示例:
不客气。
Example:
You are welcome.
我发现的最简单的方法:
Simplest way I found:
我是这样做的:将目录推送到要压缩的文件夹,运行 tar,然后弹回到之前所在的文件夹。 这不包括存档中的文件夹名称。
This is how I do it: Push directory to the folder you want to compress, run tar and then pop back to the folder you were in previously. This doesn't include the folder name in the archive.
如果文件夹是 mytemp 那么如果您应用上述内容,它将压缩并删除文件夹中的所有文件,但不理会它
您可以给出排除模式,并指定不查看子文件夹
If the folder is mytemp then if you apply the above it will zip and remove all the files in the folder but leave it alone
You can give exclude patterns and also specify not to look into subfolders too
使用 tar 的
-C
开关:-C my_directory
告诉 tar 将当前目录更改为my_directory
,然后是.< /code> 表示“添加整个当前目录”(包括隐藏文件和子目录)。
确保在执行
.
之前执行-C my_directory
,否则您将获取当前目录中的文件。警告:您将获得
./file-name.ext
形式的条目,而不是file-name.ext
!如果您需要
file-name.ext
形式的条目,请阅读其他答案。Use the
-C
switch of tar:The
-C my_directory
tells tar to change the current directory tomy_directory
, and then.
means "add the entire current directory" (including hidden files and sub-directories).Make sure you do
-C my_directory
before you do.
or else you'll get the files in the current directory.Warning: you'll get entries as
./file-name.ext
instead offile-name.ext
!If you need entries in the form of
file-name.ext
, read other answers.应该在一行中完成这项工作。 它也适用于隐藏文件。 至少在 bash 中,“*”不会通过路径名扩展来扩展隐藏文件。 下面是我的实验:
should do the job in one line. It works well for hidden files as well. "*" doesn't expand hidden files by path name expansion at least in bash. Below is my experiment:
您还可以像往常一样创建存档并使用以下命令提取它:
You can also create archive as usual and extract it with:
TL;DR(没有
./
和./file1
!)在某些条件下(仅存档文件和目录):
解释
不幸的是,下面包含一个父目录
存档中的 ./
:您可以使用
--transform
配置选项将所有文件移出该目录,但这并不能消除.< /code> 目录本身。 驯服命令变得越来越困难。
您可以使用
$(find ...)
将文件列表添加到命令中(例如 magnus'答案),但这可能会导致“文件列表太长”错误。 最好的方法是将其与 tar 的-T
选项结合起来,如下所示:基本上它的作用是列出所有文件(
-type f
)、链接(-输入 l
)和目录下的子目录(-type d
),使用-printf "%P\n"
使所有文件名相对,然后传递该文件tar 命令(它使用-T -
从 STDIN 获取文件名)。 需要-C
选项,以便 tar 知道具有相对名称的文件所在的位置。--no-recursion
标志是为了让 tar 不会递归到被告知要归档的文件夹中(导致重复文件)。如果您需要对文件名执行一些特殊操作(过滤、跟随符号链接等),
find
命令非常强大,您可以通过删除文件的tar
部分来测试它上面的命令:例如如果你想过滤PDF文件,添加
! -name '*.pdf'
非 GNU find
该命令使用
printf
(在 GNUfind
中可用)告诉find
使用相对路径打印其结果。 但是,如果您没有 GNUfind
,这可以使路径成为相对路径(使用sed
删除父级):TL;DR (no
./
and no./file1
!)With some conditions (archive only files and dirs):
Explanation
The below unfortunately includes a parent directory
./
in the archive:You can move all the files out of that directory by using the
--transform
configuration option, but that doesn't get rid of the.
directory itself. It becomes increasingly difficult to tame the command.You could use
$(find ...)
to add a file list to the command (like in magnus' answer), but that potentially causes a "file list too long" error. The best way is to combine it with tar's-T
option, like this:Basically what it does is list all files (
-type f
), links (-type l
) and subdirectories (-type d
) under your directory, make all filenames relative using-printf "%P\n"
, and then pass that to the tar command (it takes filenames from STDIN using-T -
). The-C
option is needed so tar knows where the files with relative names are located. The--no-recursion
flag is so that tar doesn't recurse into folders it is told to archive (causing duplicate files).If you need to do something special with filenames (filtering, following symlinks etc), the
find
command is pretty powerful, and you can test it by just removing thetar
part of the above command:For example if you want to filter PDF files, add
! -name '*.pdf'
Non-GNU find
The command uses
printf
(available in GNUfind
) which tellsfind
to print its results with relative paths. However, if you don't have GNUfind
, this works to make the paths relative (removes parents withsed
):看一下
--transform
/--xform
,它使您有机会在将文件添加到存档时修改文件名:Transform 表达式类似于
sed
的分隔符,我们可以使用/
以外的分隔符(上例中的,
)。https://www.gnu.org/software/tar/manual/html_section /tar_52.html
Have a look at
--transform
/--xform
, it gives you the opportunity to massage the file name as the file is added to the archive:Transform expression is similar to that of
sed
, and we can use separators other than/
(,
in the above example).https://www.gnu.org/software/tar/manual/html_section/tar_52.html
这个答案应该适用于大多数情况。 但请注意文件名如何存储在 tar 文件中,例如
./file1
而不仅仅是file1
。 我发现,当使用此方法操作 BuildRoot 中用作包文件的 tarball 时,这会导致问题。一种解决方案是使用一些 Bash glob 列出除
..
之外的所有文件,如下所示:这是我从 这个答案。
现在,如果没有与
..?*
或.[^.]*
匹配的文件, tar 将返回错误,但它仍然有效。 如果错误是一个问题(您正在检查脚本中是否成功),则此方法有效:虽然现在我们正在弄乱 shell 选项,但我们可能会认为让
*
匹配隐藏文件会更简洁:当您的 shell 在当前目录中使用
*
时,这可能不起作用,因此,也可以使用:This Answer should work in most situations. Notice however how the filenames are stored in the tar file as, for example,
./file1
rather than justfile1
. I found that this caused problems when using this method to manipulate tarballs used as package files in BuildRoot.One solution is to use some Bash globs to list all files except for
..
like this:This is a trick I learnt from this answer.
Now tar will return an error if there are no files matching
..?*
or.[^.]*
, but it will still work. If the error is a problem (you are checking for success in a script), this works:Though now we are messing with shell options, we might decide that it is neater to have
*
match hidden files:This might not work where your shell globs
*
in the current directory, so alternatively, use:这对我有用,它包含所有隐藏文件,而无需将所有文件放在名为“.”的根目录中。 就像tomoe的回答:
This one worked for me and it's include all hidden files without putting all files in a root directory named "." like in tomoe's answer :
命令
创建标准归档文件的
。
查找 my_directory/ -max深度 1 -printf "%P\n" | tar -cvf my_archive.tar -C my_directory/ -T -
打包的文件和目录位于存档的根目录中,没有路径信息,更深层次的文件具有相对路径。
文件和目录前面没有看起来奇怪的“./”。 ('./文件')
没有特殊文件“.” 被包含在内。
似乎需要另一个工具,例如
find
或ls
(ls -A -1
) 来实现这些目标,并且tar< /code> 仅使用其参数无法选择文件并创建具有此类要求的存档。
使用上面的命令创建一个归档 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
的解决方案似乎很好,但它在带有空格的文件名上失败。 不同之处在于 $() 子 shell 提供的find
的输出是空格分隔的。 可以使用 printf 添加引号,但这会使语句进一步复杂化。使用 ../my_archive.tar 作为 tar 路径时,没有理由 cd 进入 my_directory 然后再返回,因为 TAR 具有
-C DIR
、--directory=DIR
命令就是为了这个目的而存在的。使用
.
(点)将包含点使用 * 将使 shell 提供输入文件列表。 可以使用 shell 选项来包含点文件。 但这很复杂。 该命令必须在允许的 shell 中执行。 启用和禁用必须在 tar 命令之前和之后完成。 如果未来存档的根目录包含太多文件,则会失败。
最后一点也适用于所有不使用管道的解决方案。
大多数解决方案都是创建一个目录,其中包含文件和目录。 这几乎是人们所不希望的。
Command
to create a standard archive file.
find my_directory/ -maxdepth 1 -printf "%P\n" | tar -cvf my_archive.tar -C my_directory/ -T -
Packed files and dirs are in the root of the archive without path info and deeper files have relative path.
There are no weird looking './' in front of files and dirs. ('./file')
No special files '.' are included.
It seems that another tool, like
find
orls
(ls -A -1
) is needed to accomplish these goals andtar
using just its arguments is unable to pick files and create an archive with such requirements.Using above command creates an archive tar file which can be further processed or delivered to someone without looking weird or needing an explanation or a tool to unpack.
Arguments description
-maxdepth 1
Descend at most 1 level - No recursing.
-printf
print format on the standard output
%P
File's name with the name of the starting-point under which it was found removed.\n
Newlineprintf does not add a newline at the end of the string. It must be added here
tar:
-C DIR
,--directory=DIR
change to directory DIR
-T FILE
,--files-from=FILE
get names to extract or create from FILE
-
that FILE from above is the standard input, from the pipe
Comments on other solutions.
The same result might be achieved using solution described by @aross.
The difference with the solution here is in that which tool is doing the recursing. If you leave the job to
find
, every filepath name, goes through the pipe. It also sends all directory names, which tar with --no-recursion ignores or adds as empty ones followed by all files in each directory. If there was unexpected output as errors in file read fromfind
, tar would not know or care what's going on.But with further checks, like processing error stream from find, it might be a good solution where many options and filters on files are required.
I prefer to leave the recursing on tar, it does seem simpler and as such more stable solution.
With my complicated directory structure, I feel more confident the archive is complete when tar will not report an error.
Another solution using
find
proposed by @serendrewpity seems to be fine, but it fails on filenames with spaces. Difference is that output fromfind
supplied by $() sub-shell is space-divided. It might be possible to add quotes using printf, but it would further complicate the statement.There is no reason to cd into the my_directory and then back, while using ../my_archive.tar for tar path, because TAR has
-C DIR
,--directory=DIR
command which is there just for this purpose.Using
.
(dot) will include dotsUsing * will let shell supply the input file list. It might be possible using shell options to include dot files. But it's complicated. The command must be executed in shell which allows that. Enabling and disabling must be done before and after tar command. And it will fail if root dir of future archive contains too many files.
That last point also applies to all those solutions which are not using pipe.
Most of solutions are creating a dir inside which are the files and dirs. That is barely ever desired.
星号将包括所有内容,甚至是隐藏的内容
the asterisk will include everything even hidden ones
如果是Unix/Linux系统,而你关心隐藏文件(会被*漏掉),你需要这样做:
我不知道隐藏文件在Windows下是什么样子的。
If it's a Unix/Linux system, and you care about hidden files (which will be missed by *), you need to do:
I don't know what hidden files look like under Windows.
我建议使用以下 Bash 函数(第一个参数是目录的路径,第二个参数是生成的存档的基名):
您可以以这种方式运行它:
它将生成存档
my_archive.tar.gz< /code> 在当前目录中。 它适用于隐藏 (.*) 元素以及文件名中带有空格的元素。
I would propose the following Bash function (first argument is the path to the dir, second argument is the basename of resulting archive):
You can run it in this way:
and it will generate the archive
my_archive.tar.gz
within current directory. It works with hidden (.*) elements and with elements with spaces in their filename.如果您使用 bash,这可能是最简单的答案。
使用shopt -s dotglob bash 命令将:
(来自 https://stackoverflow.com/a/9776491/7726468)
测试此解决方案:
If you use bash, this could be the simplest answer.
With
shopt -s dotglob
the bash command would:(from https://stackoverflow.com/a/9776491/7726468)
Test this solution:
这对我有用。
您还可以
在第一个命令中使用 find 返回 my_dir 的文件和子目录列表。
但是,目录 my_dir 本身作为“.”包含在该列表中。
-printf 参数删除包含“.”的完整路径。 以及所有 crlf
但是,格式字符串中的 space < printf 的 em>'%P ' 在 my_dir 的文件和子目录列表中留下剩余内容并且可以通过find命令结果中的前导空格看到。
这对于 TAR 来说不是问题,但如果您想解决此问题,请添加 -min深度 1,如第二个命令中所示。
This is what works for me.
You could also use
In the first command, find returns a list of files and sub-directories of my_dir.
However, the directory my_dir is itself included in that list as '.'
The -printf parameter removes the full path including that '.' and also all crlf
However the space in the format string '%P ' of printf leaves a remnant in the list of files and sub-directories of my_dir and can be seen by a leading space in the result of the find command.
That will not be a problem for TAR but if you want to fix this, add -mindepth 1 as in the second command.
运行它比 mydir 上一级。
这不会包含任何 [.] 或其他内容。
Run it one level above mydir.
This won't include any [.] or stuff.