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

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

私の要件の最初の部分:

私はそれから単一のファイルを抽出したいと思いますex1234.zip。構造と内容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

実際のサンプル:

$ 少ないCW2178470.zip
アーカイブ: CW2178470.zip
Zipファイルサイズ:26108バイト、アイテム数:26
-rw---- 2.0 fat 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/audistory.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に一致するアーカイブ内のすべてのファイルは、現在のディレクトリから抽出されます(パスが少なくとも2つ以上一致するため、ex1234.zip深さレベル3以下のアーカイブメンバーを除く)。'*/*/*'/

現在のディレクトリのすべてのアーカイブを処理するには、次のように実行できます。

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オプションは省略可能そして、もし抽出するファイルは.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ファイルをマウントし、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

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

これよりスマートなロジックが必要な場合は、おそらくそれを見て抽出しperlますArchive::Zip

関連情報