相当于解压中tar的“--strip-components=1”?

fri*_*igg 72 zip unzip tar

我有一个将 tar.gz 文件提取到指定子目录mysubfolder 的脚本

mkdir mysubfolder; tar --extract --file=sourcefile.tar.gz --strip-components=1 --directory=mysubfolder;
Run Code Online (Sandbox Code Playgroud)

是否有使用 zip 文件执行此操作的等效方法?

Mes*_*ion 36

正如 Mathias 所说,unzip没有这样的选择,但单行 bash 脚本可以完成这项工作。

问题是:最好的方法取决于您的存档布局。如果内容直接位于存档根目录中,那么假设单个顶级目录的解决方案将惨遭失败(想想/a/foo /b/foo /foo剥离/a和的混乱/b)。

同样的失败发生在tar --strip-component. 没有一刀切的解决方案。

所以,剥离的根目录,假设有一个(并且一个):

unzip -d "$dest" "$zip" && f=("$dest"/*) && mv "$dest"/*/* "$dest" && rmdir "${f[@]}"
Run Code Online (Sandbox Code Playgroud)

只要确保第二级的文件/显示目录都没有具备顶级父的相同名称(例如,/foo/foo)。但是/foo/bar/foo/foo/bar/bar可以。如果他们这样做,或者您只是想安全,您可以使用临时目录进行提取:

temp=$(mktemp -d) && unzip -d "$temp" "$zip" && mkdir -p "$dest" &&
mv "$temp"/*/* "$dest" && rmdir "$temp"/* "$temp"
Run Code Online (Sandbox Code Playgroud)

如果您使用 Bash,您可以测试顶级是否为单个目录或不使用:

f=("$temp"/*); (( ${#f[@]} == 1 )) && [[ -d "${f[0]}" ]] && echo "Single dir!"
Run Code Online (Sandbox Code Playgroud)

说到 Bash,您应该打开dotglob以包含隐藏文件,并且您可以将所有内容包装在一个方便的函数中:

unzip -d "$dest" "$zip" && f=("$dest"/*) && mv "$dest"/*/* "$dest" && rmdir "${f[@]}"
Run Code Online (Sandbox Code Playgroud)

现在把它放在你的~/.bashrc身上,你再也不用担心它了。简单地用作:

unzip-strip sourcefile.zip [mysubfolder] [OPTIONS]
Run Code Online (Sandbox Code Playgroud)

这只小野兽会:

  • mysubfolder如果不存在,则为您创建
  • 自动检测您的 zip 存档是否包含单个顶级目录并相应地处理提取。
  • mysubfolder可选的。如果为空,它将提取到当前目录的子目录(不一定是存档目录!),命名为:
    • 存档中的单个顶级目录(如果有)
    • 或存档文件名,没有(大概.zip)扩展名
  • 如果给定或派生的目标路径已作为文件存在,则增加名称直到找到合适的路径(新路径或现有目录)。
  • 默认情况下:
    • 安静
    • 覆盖任何现有文件
    • 保留链接和属性(模式、时间戳等)
  • 额外传递OPTIONScp. 有用的选项是:
    • -v|--verbose: 输出每个复制的文件,就像unzip
    • -n|--no-clobber: 不要覆盖现有文件
    • -u|--update: 只覆盖比目标新的文件
  • 需要额外OPTIONS作为第三个参数。如果需要,制作一个适当的参数解析器。
  • 由于“提取到临时目录并复制”的方法,在操作期间使用双倍提取的磁盘空间。如果不失去一些灵活性/功能,就无法解决这个问题。


小智 10

您可以使用-j垃圾路径(不要创建目录)。这仅建议用于有些常见的单级存档。具有多级目录结构的档案将被扁平化 - 这甚至可能导致要提取的文件的名称冲突。

从解压缩的手册页:

   -j     junk  paths.   The  archive's directory structure is not recreated; all files are deposited in the
          extraction directory (by default, the current one).
Run Code Online (Sandbox Code Playgroud)


fnk*_*nkr 8

正如其他人所指出的,unzip 不支持这一点。不过,bsdtar 也可以提取 zip 文件。

bsdtar xvf app.zip --strip-components=1 -C /opt/some-app
Run Code Online (Sandbox Code Playgroud)

bsdtar 还可以提取流(unzip 不支持)。

curl -sSL https://... | bsdtar xvf - --strip-components=1 -C /opt/some-app
Run Code Online (Sandbox Code Playgroud)


Mat*_*ens 5

我在的手册页中unzip找不到这样的选项,所以恐怕这是不可能的。:(

但是,(取决于情况)您可以解决它。例如,如果您确定 zip 文件中唯一的顶级目录的名称foo-后跟版本号,您可以执行以下操作:

cd /tmp
unzip /path/to/file.zip
cd foo-*
cp -r . /path/to/destination/folder
Run Code Online (Sandbox Code Playgroud)

  • 这也是为什么永远不应该使用`/tmp/some-hardcoded-folder-name` 作为临时文件夹,而应该使用`mktemp`:它保证不会有这样的现有文件夹。在下面检查我的答案。 (3认同)
  • 不错的方法,但有点不完整:您仍然会拥有 foo* dir 以及完整提取的内容。 (2认同)