我通常这样做:
tar -czvf my_directory.tar.gz my_directory
如果我只想在 my_directory 中包含所有内容(包括任何隐藏的系统文件),而不是目录本身,该怎么办?我不想要:
my_directory
--- my_file
--- my_file
--- my_file
我想:
my_file
my_file
my_file
tar -czf
的默认行为吗?在我的情况下,它只存储文件而不是目录。当我只是 tar
它包含它的目录时,但使用 tar -czf
它只是添加文件。
使用 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
形式的条目,请阅读其他答案。
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
.
替换为 *
,那么命令将是 cd my_directory/ && tar -zcvf ../my_dir.tgz * && cd ..
,那么它将按您的预期工作。
$ (cd my_directory/ && tar -zcvf ../my_dir.tgz .)
tar
创作者的重大疏忽...
您还可以像往常一样创建存档并使用以下命令提取它:
tar --strip-components 1 -xvf my_directory.tar.gz
--strip-components
是 GNU 扩展。
.
作为根目录,这将无法解决问题。
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' 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 -
.bashrc
中为它定义一个函数,命名为 tar_content
--transform
删除 ./
(例如 --transform='s:^\./::'
)。相关:gnu.org/software/sed/manual/sed.html#Regexp-Addresses
查看 --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
file list too long
。 My solution 可以防止这种情况发生,并且也更加灵活。
--xform
。
cd my_directory
tar zcvf ../my_directory.tar.gz *
This Answer 应该适用于大多数情况。但是请注意文件名是如何存储在 tar 文件中的,例如 ./file1
而不仅仅是 file1
。我发现在使用此方法操作 BuildRoot 中用作包文件的 tarball 时,这会导致问题。
一种解决方案是使用一些 Bash glob 列出除 ..
之外的所有文件,如下所示:
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 glob *
,因此,或者,使用:
shopt -s dotglob
cd my_dir
tar -zcvf ../my_dir.tar.gz *
cd ..
shopt -u dotglob
tar: start.sh: Cannot stat: No such file or directory
这发生在我当前目录中的所有文件上!我该如何避免这种情况?
-C my_dir
) 之前,*
glob 由 shell 评估。因此,它尝试将文件归档在执行 tar 命令的当前目录中,而不是更改的目录 my_dir
。如果当前目录中的文件名恰好与更改目录中的名称 my_dir
匹配,那么您可能会很幸运,但这通常并不可靠。 :) ...最有可能的是,这就是上述错误的原因。
cd my_directory && tar -czvf ../my_directory.tar.gz $(ls -A) && cd ..
这个对我有用,它包含所有隐藏文件,而不将所有文件放在名为“。”的根目录中。就像在 tomoe's answer 中一样:
如果它是 Unix/Linux 系统,并且您关心隐藏文件(将被 * 忽略),您需要执行以下操作:
cd my_directory
tar zcvf ../my_directory.tar.gz * .??*
我不知道隐藏文件在 Windows 下是什么样子的。
.a
)的点文件。
cd DIRECTORY
tar -czf NAME.tar.gz *
星号将包括所有内容,甚至是隐藏的内容
命令
创建标准存档文件。
find my_directory/ -maxdepth 1 -printf "%P\n" | tar -cvf my_archive.tar -C my_directory/ -T -
打包的文件和目录位于存档的根目录中,没有路径信息,更深的文件具有相对路径。文件和目录前面没有奇怪的“./”。 ('./file') 没有特殊文件 '.'被包含在内。
似乎需要另一个工具,如 find
或 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
的另一个解决方案似乎很好,但它在带有空格的文件名上失败。不同之处在于由 $() 子 shell 提供的 find
的输出是按空间划分的。可以使用 printf 添加引号,但这会使语句更加复杂。
没有理由 cd 进入 my_directory 然后返回,同时使用 ../my_archive.tar 作为 tar 路径,因为 TAR 有 -C DIR
, --directory=DIR
命令,它只是用于此目的。
使用 .
(点)将包括点
使用 * 会让 shell 提供输入文件列表。可以使用 shell 选项来包含点文件。但这很复杂。该命令必须在允许的 shell 中执行。启用和禁用必须在 tar 命令之前和之后完成。如果未来存档的根目录包含太多文件,它将失败。
最后一点也适用于所有不使用管道的解决方案。
大多数解决方案都是在其中创建一个目录,其中包含文件和目录。这几乎是不可取的。
2>/dev/null
来查找。然后你保证只有文件名/路径
|
右侧的 tar
,但默认情况下会打印到控制台。
--ignore-failed-read
添加到 tar
我会提出以下 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
。它适用于隐藏 (.*) 元素和文件名中带有空格的元素。
ls
用于该 link
这对我有用。
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 参数会删除包含“.”的完整路径还有所有的 crlf 但是 printf 的格式字符串 '%P ' 中的 space 离开my_dir 的文件和子目录列表中的剩余部分,可以通过 find 结果中的前导空格看到> 命令。
这对 TAR 来说不是问题,但如果你想解决这个问题,请在第二个命令中添加 -mindepth 1。
使用派克斯。
Pax 是一个已弃用的软件包,但它以一种简单的方式完美地完成了这项工作。
pax -w > mydir.tar mydir
我发现的最简单的方法:
cd my_dir && tar -czvf ../my_dir.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=-
}
安全地处理带有空格或其他异常字符的文件名。您可以选择将 -name '*.sql'
或类似过滤器添加到 find 命令以限制包含的文件。
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 -cvzf tarlearn.tar.gz --remove-files mytemp/*
如果文件夹是 mytemp,那么如果您应用上述内容,它将压缩并删除文件夹中的所有文件,但不要管它
tar -cvzf tarlearn.tar.gz --remove-files --exclude='*12_2008*' --no-recursion mytemp/*
您可以提供排除模式,也可以指定不查看子文件夹
tar -C my_dir -zcvf my_dir.tar.gz `ls my_dir`
tar --create --file=foo.tar -C /etc passwd hosts -C /lib libc.a
” apl.jhu.edu/Misc/Unix-info/tar/tar_65.html 我总是尝试tar -czvf my_directory.tar.gz * -C my_directory
,但它不起作用。-C
位置很重要!该死的焦油...*
这样的通配符不会包含隐藏文件(这是最初的要求)。