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

Mar*_*rco 8 zip

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

# file: withdir.zip
somedir/alpha
somedir/beta
somedir/gamma
Run Code Online (Sandbox Code Playgroud)

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

somedir/alpha
somedir/beta
somedir/gamma
Run Code Online (Sandbox Code Playgroud)

现在假设以下存档:

# file: nodir.zip
alpha
beta
gamma
Run Code Online (Sandbox Code Playgroud)

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

alpha
beta
gamma
Run Code Online (Sandbox Code Playgroud)

我宁愿跑unzip -d nodir nodir.zip

nodir/alpha
nodir/beta
nodir/gamma
Run Code Online (Sandbox Code Playgroud)

如果我使用 nautilus 并右键单击“在此处提取”。它的行为与其应有的完全一样。但不幸的是,我还没有找到一个命令行开关,unzip或者 7z它会产生相同的行为。如何做到这一点?我可以使用其他工具吗(没有 GUI)?

Sté*_*las 7

我会做这样的事情(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
)
Run Code Online (Sandbox Code Playgroud)

那是:

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

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

unz unzip foo.zip
unz tar xf foo.tar.gz
Run Code Online (Sandbox Code Playgroud)

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