Extrai um único arquivo de um arquivo zip apenas conhecendo a extensão

3

Minha primeira parte do requisito:

Gostaria de extrair um único arquivo de ex1234.zip . A estrutura e o conteúdo de ex1234.zip :

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

Eu quero poder extrair apenas o arquivo ex1234.csv , mas não saberá o nome.

A segunda parte é capaz de fazer isso para todos os exXXXX.zip que estão no mesmo diretório.

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

A saída será:

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

Amostra real:

$ less CW2178470.zip
Archive:  CW2178470.zip
Zip file size: 26108 bytes, number of entries: 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/team.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/InternalContractWorkspace.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 files, 112005 bytes uncompressed, 21940 bytes compressed:  80.4%
(END)
    
por Pheanouk Pel 06.08.2015 / 18:24

5 respostas

4

Você pode usar unzip da seguinte forma:

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

onde -j significa caminhos de spam, file[.zip] é o nome do arquivo, [file] é o membro do arquivo a ser processado e [-x xfile] é a lista de membros do arquivo a serem excluídos do processamento. Todas essas opções são descritas em detalhes na página man. Então, no seu caso, executando por exemplo:

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

extrairá no diretório atual todos os arquivos correspondentes *.csv do nível de profundidade 2 no ex1234.zip archive (excluindo membros do archive do nível de profundidade 3 e abaixo como '*/*/*' significa caminhos que correspondem a pelo menos dois / ) .

Agora, para processar todos os arquivos no diretório atual que você pode executar:

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

que extrai o arquivo .csv de cada arquivo no diretório atual (é por isso que -j é necessário).
No seu caso particular, não há .csv na profundidade do nível 1, então você também pode executar:

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

que deve produzir o mesmo resultado.
Para executar e ver quais arquivos serão extraídos (seus caminhos de arquivo) sem realmente extraí-los, substitua -j por -qql :

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

Como uma nota lateral, a opção -j poderia ser omitida iff os arquivos .csv a serem extraídos estavam no nível de profundidade 1 (ou seja, nenhum diretório pai); Nesse caso, você poderia simplesmente executar:

for zipfile in *.zip; do unzip "$zipfile" '*.csv' -x '*/*'; done
    
por 07.08.2015 / 03:41
0

Tentei descompactar fornecido pelo 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
    
por 06.08.2015 / 18:39
0

Use um sistema de arquivos baseado no FUSE para acessar o arquivo zip como uma árvore de diretórios. Monte cada arquivo zip e acesse-o com o método normal (curingas do shell, cp , etc.).

Com zip por fusível :

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

Você pode fazer o mesmo com archivemount em vez de fuse-zip .

Há também o AVFS que funciona de maneira diferente: cria uma visão de todo o sistema de arquivos sob ~/.avfs ; nessa visão, se você tiver um arquivo archive /path/to/foo.zip , poderá acessá-lo como um diretório sob o nome ~/.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

Se você usar um shell com matrizes e uma maneira de obter uma lista vazia quando um curinga não corresponder, você poderá obter um script um pouco mais legível. Por exemplo, em ksh93, com zip de fusível:

#!/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

Em zsh, use csv=($z/*.csv(N)) . No bash, use csv=($z/*.csv) mas primeiro execute shopt -s nullglob .

    
por 07.08.2015 / 09:53
0

Você sugere que todos os nomes precisem corresponder:

  • O nome do arquivo ZIP
  • O nome do diretório dentro do arquivo ZIP
  • O arquivo CSV dentro do diretório

Nesse caso, tente:

for zipfile in ./*.zip; do
    base="$(basename "$zipfile" .zip)"
    unzip "$zipfile" "$base/$base.csv"
done
    
por 07.08.2015 / 13:40
0

Supondo que todos os arquivos correspondam a esse padrão - de CW2178470.zip você precisa extrair sempre CW2178470/CW2178470.csv

Isso é relativamente fácil:

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

Se você precisar de uma lógica mais inteligente do que isso, provavelmente começaria a analisar perl e Archive::Zip para extrair.

    
por 07.08.2015 / 13:48

Tags