【问题标题】:How do you recursively unzip archives in a directory and its subdirectories from the Unix command-line?如何从 Unix 命令行递归解压缩目录及其子目录中的档案?
【发布时间】:2010-09-11 14:26:22
【问题描述】:

unzip 命令没有递归解压缩档案的选项。

如果我有以下目录结构和档案:

/母亲/爱.zip /坏血病/Sea Dogs.zip /坏血病/治愈/酸橙.zip

我想将所有存档解压缩到与每个存档同名的目录中:

/母亲/爱/1.txt /母亲/爱.zip /坏血病/海狗/2.txt /坏血病/Sea Dogs.zip /坏血病/治愈/酸橙/3.txt /坏血病/治愈/酸橙.zip

我会发出什么命令?

重要的是,这不会阻塞包含空格的文件名。

【问题讨论】:

标签: unix recursion spaces unzip


【解决方案1】:

如果你想将文件解压到相应的文件夹,你可以试试这个

find . -name "*.zip" | while read filename; do unzip -o -d "`dirname "$filename"`" "$filename"; done;

适用于可处理高 I/O 的系统的多处理版本:

find . -name "*.zip" | xargs -P 5 -I fileName sh -c 'unzip -o -d "$(dirname "fileName")/$(basename -s .zip "fileName")" "fileName"'

【讨论】:

  • 这是正确的做法,因为它保留了完整的目录结构!
  • 注意 - 这不会按照要求将文件提取到与存档同名的目录中。
  • 我不知道 xargs 支持多核! ?
  • 这不会解压缩到单独的文件夹这一事实意味着它不能完全回答所提出的问题。此外,如果给定文件夹中的多个 zip 文件包含具有相同名称的文件,例如results.log 当您尝试将同一文件的多个副本解压缩到一个文件夹中时,这会导致问题。我正在 Cygwin 上尝试这个。看起来 -d "'dirname... 部分应该可以处理这个问题,但它对我不起作用。
  • 由于某种原因,第一个示例对我来说和 emlai 有同样的问题,所有解压缩的文件都进入了 zip 文件所在的目录。但是,第二个,多线程方法,不仅工作速度更快,但也将每个 zip 文件的文件放在以 zip 文件命名的目录中。完美!
【解决方案2】:

这是一种将所有 zip 文件提取到 工作目录 并涉及 find 命令和 while 循环的解决方案:

find . -name "*.zip" | while read filename; do unzip -o -d "`basename -s .zip "$filename"`" "$filename"; done;

【讨论】:

  • 注意 - 当您请求相对解压缩时,这会将所有 zip 文件解压缩到 工作目录!。见Vivek's answer
  • 嗯,似乎没有将它们全部提取到工作目录 AFAICT。我正在使用 OS X El Capitan 10.11.6 中的 UnZip 5.52。结果似乎与 Vivek 的相同。不过接受他的回答,因为它还展示了如何利用多核!
【解决方案3】:

正确处理所有文件名(包括换行符)并提取到与文件位于同一位置的目录中的解决方案,只是删除了扩展名:

find . -iname '*.zip' -exec sh -c 'unzip -o -d "${0%.*}" "$0"' '{}' ';'

请注意,您可以通过使用-o 添加它们轻松使其处理更多文件类型(例如.jar),例如:

find . '(' -iname '*.zip' -o -iname '*.jar' ')' -exec ...

【讨论】:

  • 迄今为止我发现的唯一正常工作的解决方案
  • 这是迄今为止唯一可以按要求工作的解决方案
  • 建议更改为“find .-iname...”以解压缩 .ZIP 和 .zip 文件
  • 这个似乎实际上得到了所有的 zip 文件。 xargs 解决方案由于我不明白的原因错过了一些
【解决方案4】:

您可以在单个命令行中使用 find 和 -exec 标志来完成这项工作

find . -name "*.zip" -exec unzip {} \;

【讨论】:

  • 这会将所有内容解压缩到当前目录中,而不是相对于每个子目录。它也不会解压缩到与每个存档同名的目录中。
  • 我认为正确的 -d 是留给读者的练习。该读者需要注意,-exec 仅允许在命令中使用一次 {} - 通过调用 sh 并将 {} 分配给变量来解决此问题。
  • 还要注意 -execdir 有时比 -exec 更可取。在这种情况下,我认为这无关紧要。
  • 我的 find (GNU findutils 4.4.0) 让我可以多次使用 {}... cloud@thunder:~/tmp/files$ find 。 -exec 回声 {} {} \; . . ./a ./a ./b ./b ./c ./c ./d ./d ./e ./e ./f ./f ./g ./g
  • my answer,它使用-exec,包括-d。请注意,调用sh 时必须小心,以确保不会执行像"; rm -rf /; 这样的邪恶文件名。
【解决方案5】:

这完全符合我们的要求:

解压文件:

find . -name "*.zip" | xargs -P 5 -I FILENAME sh -c 'unzip -o -d "$(dirname "FILENAME")" "FILENAME"'

以上命令不会创建重复的目录。

删除所有 zip 文件:

find . -depth -name '*.zip' -exec rm {} \;

【讨论】:

    【解决方案6】:

    使用 -r 标志的类似 gunzip 的东西?....

    递归遍历目录结构。如果命令行中指定的任何文件名是目录,gzip 将进入该目录并压缩它在其中找到的所有文件(或者在 gunzip 的情况下解压缩它们)。

    http://www.computerhope.com/unix/gzip.htm

    【讨论】:

    • 他说的是 zip 文件,而不是 gzip 文件。
    【解决方案7】:

    如果您使用的是 cygwin,basename 命令的语法会略有不同。

    find . -name "*.zip" | while read filename; do unzip -o -d "`basename "$filename" .zip`" "$filename"; done;
    

    【讨论】:

      【解决方案8】:

      我意识到这已经很老了,但当我在寻找类似的解决方案时,它是 Google 上的第一批热门产品之一,所以我将在这里发布我所做的事情。我的场景略有不同,因为我基本上只是想完全炸开一个罐子,以及其中包含的所有罐子,所以我编写了以下 bash 函数:

      function explode {
          local target="$1"
          echo "Exploding $target."
          if [ -f "$target" ] ; then
              explodeFile "$target"
          elif [ -d "$target" ] ; then
              while [ "$(find "$target" -type f -regextype posix-egrep -iregex ".*\.(zip|jar|ear|war|sar)")" != "" ] ; do
                  find "$target" -type f -regextype posix-egrep -iregex ".*\.(zip|jar|ear|war|sar)" -exec bash -c 'source "<file-where-this-function-is-stored>" ; explode "{}"' \;
              done
          else
              echo "Could not find $target."
          fi
      }
      
      function explodeFile {
          local target="$1"
          echo "Exploding file $target."
          mv "$target" "$target.tmp"
          unzip -q "$target.tmp" -d "$target"
          rm "$target.tmp"
      }
      

      请注意&lt;file-where-this-function-is-stored&gt;,如果您将其存储在一个文件中,而我碰巧将其存储在一个非交互式shell 无法读取的文件中,则需要它。如果您将函数存储在加载在非交互式 shell 上的文件中(例如,.bashrc 我相信),您可以删除整个 source 语句。希望这会对某人有所帮助。

      一点警告 - explodeFile 也会删除压缩文件,您当然可以通过注释掉最后一行来更改它。

      【讨论】:

        【解决方案9】:

        另一个有趣的解决方案是:

        DESTINY=[Give the output that you intend]
        
        # Don't forget to change from .ZIP to .zip.
        # In my case the files were in .ZIP.
        # The echo were for debug purpose.
        
        find . -name "*.ZIP" | while read filename; do
        ADDRESS=$filename
        #echo "Address: $ADDRESS"
        BASENAME=`basename $filename .ZIP`
        #echo "Basename: $BASENAME"
        unzip -d "$DESTINY$BASENAME" "$ADDRESS";
        done;
        

        【讨论】:

          【解决方案10】:

          这对我有用

          def unzip(zip_file, path_to_extract):
              """
              Decompress zip archives recursively
              Args:
                  zip_file: name of zip archive
                  path_to_extract: folder where the files will be extracted
              """
              try:
                  if is_zipfile(zip_file):
                      parent_file = ZipFile(zip_file)
                      parent_file.extractall(path_to_extract)
                      for file_inside in parent_file.namelist():
                          if is_zipfile(os.path.join(os.getcwd(),file_inside)):
                              unzip(file_inside,path_to_extract)
                      os.remove(f"{zip_file}")
              except Exception as e:
                  print(e)
          

          【讨论】:

          • 即使这个问题既没有标记为 shell 也没有标记为 python,我不明白为什么 Python 的答案会受到欢迎。如果它可能会变得有用,如果它像问题中所示的那样下降目录树而不是解压缩压缩的拉链。
          猜你喜欢
          • 2020-08-22
          • 2018-08-18
          • 1970-01-01
          • 2011-12-31
          • 1970-01-01
          • 2019-12-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多