web-dev-qa-db-ja.com

拡張子のみを知っているZipファイルから単一のファイルを抽出する

要件の最初の部分:

ex1234.Zipから1つのファイルを抽出します。 ex1234.Zipの構造と内容:

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

ex1234.csvファイルのみを抽出できるようにしたいのですが、名前がわかりません。

2番目の部分は、同じディレクトリにあるすべてのexXXXX.Zipに対してこれを実行できるようにすることです。

ex1234.Zip
ex3245.Zip
ex8829.Zip
exXXXX.Zip…

出力は次のようになります。

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

実際のサンプル:

$ less CW2178470.Zip 
アーカイブ:CW2178470.Zip 
 zipファイルサイズ:26108バイト、エントリ数:26 
-rw ---- 2.0 fat 108 bl defN 15- Aug-04 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 15-Aug-04 09:37 CW2178470/CW2178470/announcements.xml 
-rw ---- 2.0 fat 1037 bl defN 15-Aug-04 09:37 CW2178470/CW2178470 /Plan/plan.xml
-rw---- 2.0 fat 141 bl defN 15-Aug-04 09:37 CW2178470/CW2178470/Plan/tasks.xml 
-rw ---- 2.0 fat 2408 bl defN 15-Aug-04 09:37 CW2178470/CW2178470/FI_Doc208411460_doc.xml 
-rw ---- 2.0 fat 215 bl defN 15-Aug-04 09:37 CW2178470/CW2178470/MessageBoard/nb_27482kst.26ihyzj_.htm 
-rw ---- 2.0 fat 2364 bl defN 15-Aug-04 09:37 CW2178470/CW2178470/MessageBoard/messageboard.xml 
-rw ---- 2.0 fat 1250 bl defN 15-Aug-04 09:37 CW2178470/CW2178470/te am.xml 
-rw ---- 2.0 fat 22016 bl defN 15-Aug-04 09:37 CW2178470/CW2178470/Doc208411460.doc 
-rw ---- 2.0 fat 9973 bl defN 15-Aug-04 09:37 CW2178470/CW2178470/audithistory.xml 
-rw ---- 2.0 fat 6731 bl defN 15-Aug-04 09:37 CW2178470/CW2178470/ws.xml 
 -rw ---- 2.0 fat 308 bl defN 15-Aug-04 09:37 CW2178470/xsd/WSFolder.xsd 
-rw ---- 2.0 fat 4897 bl defN 15-Aug-04 09: 37 CW2178470/xsd/Task.xsd 
-rw ---- 2.0 fat 770 bl defN 15-Aug-04 09:37 CW2178470/xsd/ContractWorkspace.xsd 
-rw ---- 2.0 fat 4754 bl defN 15-Aug-04 09:37 CW2178470/xsd/AuditHistory.xsd 
-rw ---- 2.0 fat 25564 bl defN 15-Aug-04 09:37 CW2178470/xsd/CommonTypes。 xsd 
-rw ---- 2.0 fat 5657 bl defN 15-Aug-04 09:37 CW2178470/xsd/MessageBoard.xsd 
-rw ---- 2.0 fat 2471 bl defN 15- Aug-04 09:37 CW2178470/xsd/Plan.xsd 
-rw ---- 2.0 fat 337 bl defN 15-Aug-04 09:37 CW2178470/xsd/InternalContractW orkspace.xsd 
-rw ---- 2.0 fat 1045 bl defN 15-Aug-04 09:37 CW2178470/xsd/SalesContractRequest.xsd 
-rw ---- 2.0 fat 3133 bl defN 15-Aug-04 09:37 CW2178470/xsd/FolderItem.xsd 
-rw ---- 2.0 fat 906 bl defN 15-Aug-04 09:37 CW2178470/xsd/ContractRequest.xsd 
 -rw ---- 2.0 fat 8973 bl defN 15-Aug-04 09:37 CW2178470/xsd/WorkspaceTypes.xsd 
-rw ---- 2.0 fat 4645 bl defN 15-Aug-04 09: 37 CW2178470/xsd/Team.xsd 
-rw ---- 2.0 fat 781 bl defN 15-Aug-04 09:37 CW2178470/xsd/SalesContractWorkspace.xsd 
 26ファイル、112005バイトの非圧縮、21940バイト圧縮:80.4%
(END)
5
Pheanouk Pel

次のようにunzipを使用できます。

_unzip -j file[.Zip] [file] [-x xfile]
_

ここで、_-j_はジャンクパスを意味し、_file[.Zip]_はアーカイブ名、_[file]_は処理するアーカイブメンバー、_[-x xfile]_は処理から除外するアーカイブメンバーのリストです。これらのオプションはすべて、manページで詳しく説明されています。
つまり、あなたの場合、たとえば次のように実行します:

_unzip -j ex1234.Zip '*/*.csv' -x '*/*/*'
_

_*.csv_アーカイブの深度レベル2から_ex1234.Zip_に一致するすべてのファイルを現在のディレクトリに抽出します(深度レベル3以下のアーカイブメンバーは_'*/*/*'_が少なくとも2つに一致するパスを意味するため_/_)。

ここで、現在のディレクトリにあるすべてのアーカイブを処理するには、次のコマンドを実行します。

_for zipfile in *.Zip; do unzip -j "$zipfile" '*/*.csv' -x '*/*/*'; done
_

現在のディレクトリの各アーカイブから_.csv_ファイルを抽出します(そのため、_-j_が必要です)。
特定のケースでは、レベル1の深さに_.csv_がないため、次のように実行することもできます。

_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_オプションは省略できますiff抽出される_.csv_ファイルは深度レベル1にありました(つまり、親ディレクトリがありません)。その場合は、単に次のように実行できます。

_for zipfile in *.Zip; do unzip "$zipfile" '*.csv' -x '*/*'; done
_
9
don_crissti

Fuse -basedファイルシステムを使用して、Zipファイルにディレクトリツリーとしてアクセスします。各Zipファイルをマウントしてから、通常の方法(シェルのワイルドカード、cpコマンドなど)でアクセスします。

Fuse-Zip の場合:

_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
_

_Fuse-Zip_の代わりに archivemount を使用しても同じことができます。

[〜#〜] 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
_

配列でシェルを使用し、ワイルドカードが一致しない場合に空のリストを取得する方法を使用すると、少し読みやすいスクリプトを取得できます。たとえば、ksh93では、Fuse-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_を実行します。

すべての名前が一致する必要があることをお勧めします。

  • Zipファイル名
  • Zipファイル内のディレクトリ名
  • ディレクトリ内のCSVファイル

その場合は、次のことを試してください。

for zipfile in ./*.Zip; do
    base="$(basename "$zipfile" .Zip)"
    unzip "$zipfile" "$base/$base.csv"
done
0
traal

すべてのファイルがこのパターンに一致するという前提で-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を調べて抽出します。

0
Sobrique

Debianが提供するunzipを試してみました:

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

for file in ex*.Zip
do
  unzip -j $file '*.csv'
done
0
Mounaam