从仅知道扩展名的 zip 文件中提取单个文件

从仅知道扩展名的 zip 文件中提取单个文件

我的要求的第一部分:

我想从 中提取单个文件ex1234.zip。结构和内容ex1234.zip

ex1234 (directory)
    directory1
    ex1234 (directory)
    directory2
    ex1234.csv

我希望能够仅提取ex1234.csv文件但不知道名称。

第二部分是能够对exXXXX.zip同一目录中的所有内容执行此操作。

ex1234.zip
ex3245.zip
ex8829.zip
exXXXX.zip…

输出将是:

ex1234.csv
ex3245.csv
ex8829.csv
exXXXX.csv

真实样品:

$ 少 CW2178470.zip
存档:CW2178470.zip
Zip 文件大小:26108 字节,条目数:26
-rw---- 2.0 脂肪 108 bl defN 2004 年 8 月 15 日 09:37 CW2178470/CW2178470.csv
-rw---- 2.0 fat 1363 bl defN 15-Aug-04 09:37 CW2178470/config/BusinessContactApprovers.csv
-rw---- 2.0 fat 158 bl defN 2004 年 8 月 15 日 09:37 CW2178470/CW2178470/announcements.xml
-rw---- 2.0 fat 1037 bl defN 2004 年 8 月 15 日 09:37 CW2178470/CW2178470/Plan/plan.xml
-rw---- 2.0 fat 141 bl defN 2004 年 8 月 15 日 09:37 CW2178470/CW2178470/Plan/tasks.xml
-rw---- 2.0 fat 2408 bl defN 2004 年 8 月 15 日 09:37 CW2178470/CW2178470/FI_Doc208411460_doc.xml
-rw---- 2.0 fat 215 bl defN 2004 年 8 月 15 日 09:37 CW2178470/CW2178470/MessageBoard/nb_27482kst.26ihyzj_.htm
-rw---- 2.0 fat 2364 bl defN 2004 年 8 月 15 日 09:37 CW2178470/CW2178470/MessageBoard/messageboard.xml
-rw---- 2.0 fat 1250 bl defN 2004 年 8 月 15 日 09:37 CW2178470/CW2178470/team.xml
-rw---- 2.0 fat 22016 bl defN 2004 年 8 月 15 日 09:37 CW2178470/CW2178470/Doc208411460.doc
-rw---- 2.0 fat 9973 bl defN 2004 年 8 月 15 日 09:37 CW2178470/CW2178470/audhistory.xml
-rw---- 2.0 fat 6731 bl defN 2004 年 8 月 15 日 09:37 CW2178470/CW2178470/ws.xml
-rw---- 2.0 fat 308 bl defN 2004 年 8 月 15 日 09:37 CW2178470/xsd/WSFolder.xsd
-rw---- 2.0 fat 4897 bl defN 2004 年 8 月 15 日 09:37 CW2178470/xsd/Task.xsd
-rw---- 2.0 fat 770 bl defN 2004 年 8 月 15 日 09:37 CW2178470/xsd/ContractWorkspace.xsd
-rw---- 2.0 fat 4754 bl defN 2004 年 8 月 15 日 09:37 CW2178470/xsd/AuditHistory.xsd
-rw---- 2.0 fat 25564 bl defN 2004 年 8 月 15 日 09:37 CW2178470/xsd/CommonTypes.xsd
-rw---- 2.0 fat 5657 bl defN 2004 年 8 月 15 日 09:37 CW2178470/xsd/MessageBoard.xsd
-rw---- 2.0 fat 2471 bl defN 2004 年 8 月 15 日 09:37 CW2178470/xsd/Plan.xsd
-rw---- 2.0 fat 337 bl defN 2004 年 8 月 15 日 09:37 CW2178470/xsd/InternalContractWorkspace.xsd
-rw---- 2.0 fat 1045 bl defN 2004 年 8 月 15 日 09:37 CW2178470/xsd/SalesContractRequest.xsd
-rw---- 2.0 fat 3133 bl defN 2004 年 8 月 15 日 09:37 CW2178470/xsd/FolderItem.xsd
-rw---- 2.0 fat 906 bl defN 2004 年 8 月 15 日 09:37 CW2178470/xsd/ContractRequest.xsd
-rw---- 2.0 fat 8973 bl defN 2004 年 8 月 15 日 09:37 CW2178470/xsd/WorkspaceTypes.xsd
-rw---- 2.0 fat 4645 bl defN 2004 年 8 月 15 日 09:37 CW2178470/xsd/Team.xsd
-rw---- 2.0 fat 781 bl defN 2004 年 8 月 15 日 09:37 CW2178470/xsd/SalesContractWorkspace.xsd
26 个文件,未压缩 112005 字节,压缩 21940 字节:80.4%
(结尾)

答案1

你可以unzip这样使用:

unzip -j file[.zip] [file] [-x xfile]

其中-j表示垃圾路径,file[.zip]是您的存档名称,[file]是要处理的存档成员,[-x xfile]是要从处理中排除的存档成员的列表。所有这些选项都在手册页中详细描述。
所以在你的情况下,运行例如:

unzip -j ex1234.zip '*/*.csv' -x '*/*/*'

将在当前目录中提取存档*.csv中深度级别 2匹配的所有文件ex1234.zip(不包括深度级别 3 及以下的存档成员,因为'*/*/*'路径至少匹配两个/)。

现在,要处理当前目录中的所有档案,您可以运行:

for zipfile in *.zip; do unzip -j "$zipfile" '*/*.csv' -x '*/*/*'; done

.csv它从当前目录中的每个存档中提取文件(这就是-j需要的原因)。
在您的特定情况下,没有.csv1 级深度,因此您也可以运行:

for zipfile in *.zip; do unzip -j "$zipfile" '*.csv' -x '*/*/*'; done

这应该会产生相同的结果。
要试运行并查看将提取哪些文件(其存档路径)而不实际提取它们,请替换-j-qql

for zipfile in *.zip; do unzip -qql "$zipfile" '*/*.csv' -x '*/*/*'; done

作为旁注,该-j选项可以省略当且仅当要提取的文件.csv位于深度级别 1(即没有父目录);在这种情况下你可以简单地运行:

for zipfile in *.zip; do unzip "$zipfile" '*.csv' -x '*/*'; done

答案2

尝试使用 Debian 提供的解压:

UnZip 6.00 of 20 April 2009, by Debian. Original by Info-ZIP.

for file in ex*.zip
do
  unzip -j $file '*.csv'
done

答案3

用一个保险丝基于文件系统以目录树的形式访问 zip 文件。挂载每个 zip 文件,然后使用正常方法(shell 通配符、cp命令等)访问它。

保险丝拉链:

mkdir mnt
for z in *.zip; do
  fuse-zip -- "$z" mnt
  set mnt/*.csv
  if [ $# -gt 1 ]; then
    echo "Skipping $z because it contains multiple .csv files"
  elif ! [ -e "$1" ]; then
    echo "Skipping $z because it does not contain a .csv file"
  else
    cp -- "$1" "${z%.zip}.csv"
  fi
  fusermount -u mnt
done

你可以用同样的方法archivemount代替fuse-zip

还有AVFS其工作方式不同:它在 ; 下创建整个文件系统的视图~/.avfs;在此视图中,如果您有存档文件/path/to/foo.zip,则可以将其作为名称下的目录进行访问~/.avfs/path/to/foo.zip#

mountavfs
cd "$HOME/.avfs$PWD"
for z in *.zip; do
  set -- "$z#/"*.csv
  if [ $# -gt 1 ]; then
    echo "Skipping $z because it contains multiple .csv files"
  elif ! [ -e "$1" ]; then
    echo "Skipping $z because it does not contain a .csv file"
  else
    cp "$1" "${z%.zip}.csv"
  fi
done

如果您使用带有数组的 shell 以及在通配符不匹配时获取空列表的方法,则可以获得稍微更具可读性的脚本。例如,在 ksh93 中,使用 fusion-zip:

#!/bin/ksh
mkdir mnt
for z in *.zip; do
  fuse-zip -- "$z" mnt
  csv=(~(N)"$z/"*.csv)
  if ((${#csv[@]} > 1)); then
    echo "Skipping $z because it contains multiple .csv files"
  elif ((${#csv[@]} == 0)); then
    echo "Skipping $z because it does not contain a .csv file"
  else
    cp -- "$1" "${z%.zip}.csv"
  fi
  fusermount -u mnt
done

在 zsh 中,使用csv=($z/*.csv(N)).在 bash 中,使用csv=($z/*.csv)但首先运行shopt -s nullglob.

答案4

假设所有文件都匹配此模式 -CW2178470.zip您需要始终从中提取CW2178470/CW2178470.csv

这相对容易:

for i in ./*.zip
do
   SERIAL=$(echo "$i" | sed -e 's,^.*/,,' -e 's,.zip$,,' )
   unzip "$i" "${SERIAL}/${SERIAL}.csv"
done

如果您需要比这更智能的逻辑,我可能会开始查看perlArchive::Zip提取。

相关内容