假设我有一个如下文件结构:
/
file0.txt
file00.txt
--folderA
fileA1.txt
fileA2.txt
--folderB
fileB.dat
fileB.txt
noisefile.noise123
--folderBB
fileBB1.dat
fileBB2.dat
fileBB.txt
noisefile.noise6hy
/
并使用以下命令创建一个 zip 文件(来自):
zip -r archive.zip /*.txt /folderA/*.txt /folderB -x /folderB/noisefile.\*
此命令不保留原始文件结构,当我解压它时,它不会解压到原来的位置。有没有办法实现这一点,无论是否使用(其他可用工具)zip
?
类似的类比是包含所有结构的.deb
文件,安装时将其提取到原始位置。我不使用文件的原因是它将安装(注册?)在系统上,而我想要做的只是备份和恢复文件。也许可以做我想做的事,但我不知道?data.tar.gz
deb
deb
答案1
一般方式
每个存储相对路径并提取当前工作目录中文件的归档器都可以“强制”执行您想要的操作。您需要
/
像问题中那样从根目录()创建一个档案(提供绝对路径可能就足够了,即使您在另一个目录中);- 从根目录提取档案。
所以cd /
(或pushd /
)至关重要。
这尤其适用于zip
。我将您的问题视为简化流程、摆脱 的请求cd /
。能够相对于真实工作目录解释目标文件(在问题中)的能力archive.zip
也很好;显然是在cd /
archive.zip
之后/archive.zip
。
和tar
所需的功能在 中可用tar
。在 Linux 中,tar
是一个常见的归档器,尽管 POSIX 并不要求如此(POSIX 归档器是pax
)。
使用tar
,它的--absolute-names
/-P
选项对于您的情况很有用。手册状态:
--absolute-names -P
通常在创建档案时,会从成员名称中
tar
删除首字母/
,而从档案中提取时,tar
如果名称具有首字母/
或内部字母,则会对其进行特殊处理..
。此选项可禁用该行为。请参阅章节绝对文件名。
要实现你想要的目标,有几个条件:
- 创建存档时,您需要提供要存档的文件的绝对路径。在您的示例中,
/*.txt /folderA/*.txt /folderB
扩展为绝对路径。请注意,shell 会扩展未加引号的*
; 然后tar
(或zip
在示例中)接收扩展的路径。 - 创建档案时,您需要使用
-P
(或--absolute-names
)。如果不使用 ,tar
则将存储每个路径而不使用前导/
(您仍然可以在 中提取文件/
,这正是上面介绍的通用方法)。 - 提取时,您需要
-P
再次使用。如果不这样做,无论如何tar
都会从每个路径中删除前导/
,并且您将重新创建存储的目录树作为当前工作目录的子树。请注意,您仍然需要在提取时明确请求所需的行为,调整后的压缩命令是不够的。请参阅下一段以了解为什么这是一件好事。
相较于一般方式的优点:
- 可以将要创建的档案(例如
archive.tar
)指定为相对于真实工作目录的路径。 - 您可以将某些路径(要存档的文件)指定为相对路径,将其他路径指定为绝对路径。问题是关于所有绝对路径,但一般来说,您可能希望混合使用它们。
补充笔记:
zip
充当归档器和压缩器。这不太像 Unix(参见“专心做好一件事”)。如果要使用 进行压缩tar
,请压缩生成的存档或告诉tar
压缩在创作过程中即时进行。- 在示例中,您
-r
启用了递归。tar
这是默认行为。 - 在示例中,您曾
-x
排除一些文件。使用tar
它将类似于--exclude=/folderB/noisefile.\*
或--exclude='noisefile.*'
(此命令还将排除 中的一个文件folderBB
)。阅读这。
例子:
# archiving
tar -cPzf archive.tgz --exclude='noisefile.*' /*.txt /folderA/*.txt /folderB
# extracting
tar -xPf archive.tgz
为什么默认不提取绝对路径?
默认行为是提取相对于当前工作目录的每个路径,这是一件好事。这样,即使您是 root 用户,也不必担心某些存档(您希望只提取当前工作目录中的文件)是否是恶意的,并在其他地方提取文件(例如,它可能会覆盖/etc/passwd
或诸如此类)。您可以通过以下方式允许这种潜在的危险行为:有意而明确地选择它(事先cd /
或使用非默认选项tar -P
)。
如果我真的想要默认使用绝对路径吗?
此别名
alias tar='tar -P' # but think twice
将在交互式 shell 中的每个调用中注入相关选项tar
。或者,可以使用包装器函数或包装器脚本来注入选项。即使从另一个脚本调用,包装器脚本也可以轻松工作(相比之下:通常别名在脚本中不起作用)。
通用方法也可以作为给定归档器的脚本来实现,尽管最基本的方法(在/
调用实际归档器之前仅将目录更改为)将导致相对于 进行解释的相对路径/
,而不管当前工作目录如何。这可以通过适当的命令行解析和内部逻辑来修复;但通常这不是一项简单的任务。
反正我不建议改变默认行为。上一段解释了原因。如果我是你,我会接受提取时需要非默认操作;我会执行它们有意地无论何时。
提示
常规方法是将您置于根目录中。您可能希望cd
返回到您的真实工作目录。有用的技巧:
cd -
相当于cd "$OLDPWD" && pwd
。这是返回的基本方法cd
。pushd /
cd /
而不是popd
在末尾输入 ,。我知道输入cd /
and会更快cd -
,但如果您在日常工作中习惯了pushd
+,popd
那么您可能会在这种情况下自然而然地使用它们,而不会再三考虑,也不会破坏您的习惯。子 shell,例如
(cd / && unzip …)
。这不会更改主 shell 中的当前工作目录。由于变量在整个子 shell 执行之前展开,因此这个技巧特别有用;这意味着您可以使用 来$PWD
传递您的真实工作目录:(cd / && unzip "$PWD"/archive.zip)