如何判断“解压缩”是否会提前创建单个文件夹?

use*_*828 8 zip

一个常见的场景是在一个目录中有一个包含其他工作的 zip 文件:

me@work ~/my_working_folder $ ls
downloaded.zip  workfile1  workfile2  workfile3
Run Code Online (Sandbox Code Playgroud)

我想解压缩downloaded.zip,但我不知道它是否会弄得一团糟,或者它是否很好地创建了自己的目录。我正在进行的解决方法是创建一个临时文件夹并将其解压缩到那里:

me@work ~/my_working_folder $ mkdir temp && cp downloaded.zip temp && cd temp
me@work ~/my_working_folder/temp $ ls
downloaded.zip
me@work ~/my_working_folder/temp $ unzip downloaded.zip 
Archive:  downloaded.zip
   creating: nice_folder/
Run Code Online (Sandbox Code Playgroud)

这可以防止my_working_folder填充大量 zip 文件内容。

我的问题是:有没有更好的方法来确定一个 zip 文件在解压前是否只包含一个文件夹?

n.s*_*.st 7

好吧,您可以无条件地提取到一个子目录中,然后如果它最终只包含一个项目,则将其删除。

但是,当您可以使用时,为什么要寻求一个理智而简单的解决方案(由ilkkachu 提供awk呢?:)

sunzip ()
{
    if [ $# -ne 1 ] || ! [ -f "$1" ]
    then
        printf '%s\n' "Expected a filename as the first (and only) argument. Aborting."
        return 1
    fi

    extract_dir="."

    # Strip the leading and trailing information about the zip file (leaving
    # only the lines with filenames), then check to make sure *all* filenames
    # contain a /.
    # If any file doesn't contain a / (i.e. is not located in a directory or is
    # a directory itself), exit with a failure code to trigger creating a new
    # directory for the extraction.
    if ! unzip -l "$1" | tail -n +4 | head -n -2 | awk 'BEGIN {lastprefix = ""} {if (match($4, /[^/]+/)) {prefix=substr($4, RSTART, RLENGTH); if (lastprefix != "" && prefix != lastprefix) {exit 1}; lastprefix=prefix}}'
    then
        extract_dir="${1%.zip}"
    fi

    unzip -d "$extract_dir" "$1"
}
Run Code Online (Sandbox Code Playgroud)

又快又脏。适用于 InfoZIP 的unzipv6.0。
您可能希望根据您的需要调整它,例如接受或自动使用附加参数unzip,或为提取子目录使用不同的名称(当前由zip文件名确定)。


哦,我刚刚注意到这个解决方法正确地处理了两种最常见的情况(1. ZIP 文件包含一个包含内容的单个目录,2. ZIP 文件包含许多单独的文件和/或目录),但不会创建一个ZIP 文件的根目录包含多个目录但没有文件时的子目录...

编辑:固定。该awk脚本现在存储 ZIP 文件中包含的每个路径的第一个组件(“前缀”),并在检测到与前一个不同的前缀时立即中止。这会捕获多​​个文件和多个目录(因为两者都必须具有不同的名称),同时忽略所有内容都包含在同一子目录中的 ZIP 文件。

  • 请注意,如果文件名包含空格,则只会在第一个空格之前的部分中找到斜杠。虽然它只会创建无用的额外目录。 (3认同)
  • @ilkkachu 当可以使用 `awk` 代替时,为什么要寻求一种理智而简单的解决方案?:) (2认同)

Chr*_*her 5

从手册...

[-d 目录]

将文件提取到的可选目录。默认情况下,所有文件和子目录都会在当前目录中重新创建;-d 选项允许在任意目录中提取(始终假设有权写入该目录)。该选项不需要出现在命令行的末尾;它也可以在 zipfile 规范之前(使用正常选项)、紧接在 zipfile 规范之后或在文件和 -x 选项之间接受。选项和目录可以连接在一起,之间没有任何空格,但请注意,这可能会导致正常的 shell 行为被抑制。特别是, -d ~(波浪号) 由 Unix C shell 扩展为用户主目录的名称,但-d~被视为~当前目录的字面子目录。

所以...

unzip -d new_dir zipfile.zip
Run Code Online (Sandbox Code Playgroud)

这将创建一个目录 new_dir,并提取其中的存档,这样即使不先查看,也可以避免每次潜在的混乱。看看也很有用man unzip手册页的更多帮助

  • 是的,但是如果存档*确实*包含单个目录中的所有内容,那么您就会有一个额外的不需要的目录层。 (4认同)

Ste*_*itt 5

您也可以使用以下命令来提取它,而不是在提取它之前检查存档内容,unar这将提供您\xe2\x80\x99re之后的行为:默认情况下,如果存档包含单个顶级目录,unar则按原样提取它,否则,它会创建一个以存档命名的目录并将其解压到那里。您可以使用以下命令在所有情况下强制创建目录-d

\n\n

unar它还具有支持多种存档格式的优点。

\n