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

362 gzip tar archive

我通常这样做:

tar -czvf my_directory.tar.gz my_directory
Run Code Online (Sandbox Code Playgroud)

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

my_directory
   --- my_file
   --- my_file
   --- my_file
Run Code Online (Sandbox Code Playgroud)

我想要:

my_file
my_file
my_file
Run Code Online (Sandbox Code Playgroud)

dub*_*bek 630

使用-Ctar 的开关:

tar -czvf my_directory.tar.gz -C my_directory .
Run Code Online (Sandbox Code Playgroud)

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

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

  • 不完美 - tar文件包含'.' 还有./file1而不仅仅是file1.我喜欢下面mateusza的解决方案,在无目标时使用--strip-components. (54认同)
  • 它创建 .作为.tar.gz中的根目录. (25认同)
  • "与大多数选项不同,-C在处理的文件列表中处理.请考虑以下命令:`tar --create --file = foo.tar -C/etc passwd hosts -C/lib libc.a`"http://www.apl.jhu.edu/Misc/Unix-info/tar/tar_65.html我总是尝试`tar -czvf my_directory.tar.gz*-C my_directory`但这不起作用.`-C`位置很重要!该死的焦油...... (14认同)
  • +1谢谢!这该死的'.' 我失踪了.如此恶化 (5认同)
  • @Superole:在运行tar之前,_shell_替换了通配符.另请注意,使用像`*`这样的通配符不会包含隐藏文件(这是原始要求). (3认同)
  • 对于那些不想要`.` 父目录的人,[这里是解决方案](http://stackoverflow.com/a/39530409/1000608) (3认同)
  • 奇怪的是`-C`如果与通配符通配符组合就会失败.它遍布_real_ current目录,然后尝试查找_tar_ current目录中的文件.`tar cf foo.tar -C/lib lib*`导致`tar:lib*:无法统计:没有这样的文件或目录` (2认同)

小智 217

cd my_directory/ && tar -zcvf ../my_dir.tgz . && cd - 
Run Code Online (Sandbox Code Playgroud)

应该在一条线上完成这项工作.它也适用于隐藏文件."*"不会通过路径名扩展来扩展隐藏文件,至少在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
Run Code Online (Sandbox Code Playgroud)

  • 不完美 - tar文件包含'.' 还有./file1而不仅仅是file1.我喜欢下面mateusza的解决方案,在无目标时使用--strip-components. (25认同)
  • @Ivan如果用`*`替换`.`,那么命令将是`cd my_directory/&& tar -zcvf ../my_dir.tgz*&& cd ..`然后它将按预期工作. (19认同)
  • 有谁知道为什么这么复杂?似乎是“tar”创建者的一个重大疏忽...... (10认同)
  • 在当前的 ubuntu 上,这给了我一个名为“.”的文件夹的存档。在里面。 (5认同)
  • @jmathew您还可以使用子外壳,以使当前外壳的工作目录不变:`$(cd my_directory / && tar -zcvf ../my_dir.tgz。) (3认同)
  • 这也适用于带有空格或其他特殊字符的文件。做得好! (2认同)

mat*_*sza 55

您也可以像往常一样创建存档并使用以下内容解压缩:

tar --strip-components 1 -xvf my_directory.tar.gz
Run Code Online (Sandbox Code Playgroud)

  • 请注意,`--strip-components` 是一个 GNU 扩展。 (4认同)
  • 可以通过在上下文中提供“照常”示例来改进此答案。 (4认同)
  • 在您使用所有需求之前创建的tarball时,此解决方案尤其适用... (3认同)
  • 如果 tar 的创建在我这边,但提取不在我这边,并且不希望有“.”作为根目录,这将无法解决问题。 (3认同)

Mag*_*nus 32

看一下--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
Run Code Online (Sandbox Code Playgroud)

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

  • 我会这样做的.别的什么只是一个黑客! (3认同)
  • 这是一个更好的解决方案. (2认同)

aro*_*oss 22

TL; DR

find /my/dir/ -printf "%P\n" | tar -czf mydir.tgz --no-recursion -C /my/dir/ -T -
Run Code Online (Sandbox Code Playgroud)

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

find /my/dir/ -printf "%P\n" -type f -o -type l -o -type d | tar -czf mydir.tgz --no-recursion -C /my/dir/ -T -
Run Code Online (Sandbox Code Playgroud)

说明

不幸的是,下面包含了./存档中的父目录:

tar -czf mydir.tgz -C /my/dir .
Run Code Online (Sandbox Code Playgroud)

您可以使用--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 -
Run Code Online (Sandbox Code Playgroud)

基本上它的作用是列出你目录下的所有文件(-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
Run Code Online (Sandbox Code Playgroud)

例如,如果要过滤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
Run Code Online (Sandbox Code Playgroud)

非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 -
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案。非常细致,最重要的是,完美解决了问题。 (2认同)

Rob*_*her 16

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

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

tar -C my_dir -zcvf my_dir.tar.gz .[^.]* ..?* *
Run Code Online (Sandbox Code Playgroud)

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

现在,如果没有匹配的文件焦油将返回错误..?*.[^.]*,但它仍然可以工作.如果错误是一个问题(您正在检查脚本中的成功),这可以工作:

shopt -s nullglob
tar -C my_dir -zcvf my_dir.tar.gz .[^.]* ..?* *
shopt -u nullglob
Run Code Online (Sandbox Code Playgroud)

虽然现在我们正在搞乱shell选项,但我们可能会认为*匹配隐藏文件比较简洁:

shopt -s dotglob
tar -C my_dir -zcvf my_dir.tar.gz *
shopt -u dotglob
Run Code Online (Sandbox Code Playgroud)

这可能不适*用于当前目录中的shell globs ,因此,使用:

shopt -s dotglob
cd my_dir
tar -zcvf ../my_dir.tar.gz *
cd ..
shopt -u dotglob
Run Code Online (Sandbox Code Playgroud)

  • 执行此操作时出现奇怪的错误 `tar: start.sh: Cannot stat: No such file or directory` 我当前目录中的所有文件都会发生这种情况!我如何避免这种情况? (2认同)

mat*_*sza 14

cd my_directory
tar zcvf ../my_directory.tar.gz *
Run Code Online (Sandbox Code Playgroud)

  • Hal明确询问了隐藏文件.你还需要.??*. (2认同)
  • -1:这不会将隐藏文件添加到tar。请参阅tbman的答案。 (2认同)

小智 6

cd my_directory && tar -czvf ../my_directory.tar.gz $(ls -A) && cd ..
Run Code Online (Sandbox Code Playgroud)

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

  • 如果由“ls”提供的文件或目录名称包含空格,“tar”将中断。[更多不使用 ls 的原因](http://mywiki.wooledge.org/BashPitfalls#for_f_in_.24.28ls_.2A.mp3.29) (2认同)