如果 zip 存档包含多个文件,则创建目录

如果 zip 存档包含多个文件,则创建目录

如果存档在根目录中包含多个文件,我想创建一个以文件名命名的目录(不带扩展名)。如果存档仅包含一个目录,那么我想简单地提取它。假设我有以下存档:

# file: withdir.zip
somedir/alpha
somedir/beta
somedir/gamma

如果我将其提取到当前目录中,我希望将其简单地提取(unzip withdir.zip):

somedir/alpha
somedir/beta
somedir/gamma

现在假设有以下存档:

# file: nodir.zip
alpha
beta
gamma

当我运行时,unzip nodir.zip我最终会用三个文件弄乱当前目录:

alpha
beta
gamma

我宁愿跑unzip -d nodir nodir.zip

nodir/alpha
nodir/beta
nodir/gamma

如果我使用 nautilus 并右键单击“Extract Here”。它的行为完全符合预期。但不幸的是,我还没有找到unzip7z产生相同行为的命令行开关。如何实现这一目标?我可以使用其他工具(无 GUI)吗?

答案1

我会做这样的事情(zsh 语法):

unz() (
  tmp=$(TMPDIR=. mktemp -d -- ${${argv[-1]:t:r}%.tar}.XXXXXX) || exit
  print -r >&2 "Extracting in $tmp"
  cd -- $tmp || exit
  [[ $argv[-1] = /* ]] || argv[-1]=../$argv[-1]
  (set -x; "$@"); ret=$?
  files=(*(ND[1,2]))
  case $#files in
    (0) print -r >&2 "No file created"
        rmdir -v "../$tmp";;
    (1) mv -v -- $files .. && rmdir -v ../$tmp;;
    (*) mv -vT ../$tmp ../$tmp:r;;
  esac && exit $ret
)

那是:

  1. 无论如何创建一个目录
  2. 运行命令
  3. 取决于命令生成的文件数量:
    • 删除该目录(如果它没有创建任何文件)
    • 如果它只创建了一个文件/目录,请将其向上移动一级并丢弃我们的目录
    • 否则,尝试从临时目录末尾删除随机字符串。

这样,您可以执行以下操作:

unz unzip foo.zip
unz tar xf foo.tar.gz

它假定提取命令的最后一个参数是要提取的文件。它还假定-v选项使用 GNU 工具。在非 GNU 系统上,您可以删除它们并可能手动进行日志记录。mv -T也是 GNU 特定的,并且mv仅强制尝试进行重命名。

答案2

由于unzip两者7z都有一个输出到给定目录的开关,您可以创建一个简单的脚本,检查存档根目录中有多少个文件,然后根据需要添加开关。

对于 7z,这更容易,因为它有开关-slt,这使得输出更易于机器读取。对于 zip 中的每个文件,输出都将包含一行Path = ...。根目录中的文件不应包含任何/值。

我编写了一个通过这种方式解压文件的简单脚本:

#!/bin/sh
for archive in "$@"; do
    # count files in root dir
    rootfiles=$(7z l -slt "${archive}" | grep -c 'Path = [^/]*$')

    # add -o switch, if more than one file in root
    # checks for >2, because path of the zip file itself is listed too
    if [ $rootfiles -gt 2 ]; then
        filename=${archive##*/}
        rootname=${filename%.*}
        opt="-o${rootname}"
    fi

    #unpack
    7z x "${opt}" "${archive}"
done

编辑:脚本现在也适用于 zip

答案3

巡警处理不同类型的存档并在存档包含多个文件的情况下创建子目录,以防止提取的文件使工作目录混乱。

创建档案

patool create archive.zip somedirectory

提取存档

patool extract archive.zip

要获取支持的格式列表,请使用patool formats

答案4

你也可以使用乌纳尔,当有两个或多个顶级文件时,它默认创建一个包含目录:

$ touch 1 2
$ zip a.zip 1 2
  adding: 1 (stored 0%)
  adding: 2 (stored 0%)
$ unzip -l a.zip
Archive:  a.zip
  Length     Date   Time    Name
 --------    ----   ----    ----
        0  04-29-14 10:56   1
        0  04-29-14 10:56   2
 --------                   -------
        0                   2 files
$ unar a.zip
a.zip: Zip
  1  (0 B)... OK.
  2  (0 B)... OK.
Successfully extracted to "a".
$ ls a
1 2

添加-d以始终创建包含目录。

相关内容