maneira CLI para compactar arquivos individuais atualmente na pasta compactada

5

Eu tenho um arquivo compactado Data.zip que (se descompactado) contém muitos arquivos:

file_1.txt    
file_2.txt
...    
... 

Eu quero ter um comando da CLI para transformar isso em uma nova pasta Data_zipped que contém os arquivos individuais em Data.zip descompactados:

Data_zipped/file_1.zip     
Data_zipped/file_2.zip
...
...

Mas o truque é que Data.zip contém tantos arquivos (e eles são coletivamente tão grandes) que eu não posso primeiro descompactar o Data.zip e depois compactar os arquivos individuais dentro dele de uma só vez: tudo tem que ser acontecer 'on the fly':

Para todos os arquivos em Data.zip/

  1. obtenha o arquivo i-ésimo
  2. compactá-lo em name_of_that_file.zip
  3. armazena o arquivo compactado na nova pasta Data_zipped

Como fazer isso usando o CLI?

Eu modifiquei o @ George script super claro para ajudar a explicar melhor a estrutura da pasta:

#!/bin/bash

#Name of zip file
filename=$1

# Check if valid zip file is passed
if [[ $(file "$filename" | grep -o "Zip archive data") =~ "Zip archive data" ]]
then    

        # List the contents of the zip file
        unzip -l "$filename" 

        # Get the number of files in zip file
        count=$(unzip -l "$filename" | awk '{count = $2 - 2} END {print count}')

        echo "$count"

fi

exit 0

Quando eu executo eu recebo (eu uso um token Data.zip com apenas alguns arquivos nele, mas você tem a idéia):

./GU_script.sh Data.zip
Archive:  Data.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  2017-11-21 22:58   Data/
120166309  2017-11-21 14:58   Data/Level1_file.csv
120887829  2017-11-21 14:58   Data/Level1_other_file.csv
163772796  2017-11-21 14:59   Data/Level1_yet_other_file.csv
193519556  2017-11-21 14:59   Data/Level1_here_is_another_file.csv
153798779  2017-11-21 14:59   Data/Level1_so_many_files.csv
131918225  2017-11-21 14:59   Data/Level1_many_more_to_go.csv
---------                     -------
884063494                     7 files
5

Então, basicamente, eu gostaria que Level1_file.csv e os outros arquivos fossem compactados individualmente (- > Level1_file.zip) e colocados em uma pasta.

Editar2;

Acabei combinando as respostas de @ George e @David Foerster:

#!/bin/bash

#Name of zip file
filename="$1"

# Check if valid zip file is passed
if file "$filename" | grep -wq "Zip archive data";
then    

        #!/bin/bash
    src="$filename"
    dst=.

    LC_ALL=C unzip -l "$src" |
    sed -re '1,/^-{6}/d; /^-{6}/,$d; /\/$/d; s/^\s*(\S+\s+){3}//' |
    while IFS= read -r f; do
        out="${f##*/}"; out="$dst/${f%%/*}_zipped/${out%.*}.zip"
        if [ ! -d "${out%/*}" ]; then
        mkdir -p "${out%/*}" || break
        fi
        zip --copy "$src" --out "$out" "$f" || break
    done           

else
        echo "Invalid file type: \"zip\" file required"
        exit 1
fi
    
por user2413 23.11.2017 / 19:27

4 respostas

6

Você pode usar a operação de "cópia" de zip(1) e algum mangling de caminho de arquivo. Ele tem a vantagem de copiar os fluxos de dados compactados diretamente para o arquivo de destino sem descompressão intermitente.

#!/bin/bash
src=Data.zip
dst=.

LC_ALL=C unzip -l "$src" |
sed -re '1,/^-{6}/d; /^-{6}/,$d; /\/$/d; s/^\s*(\S+\s+){3}//' |
while read -r f; do
    out="${f##*/}"; out="$dst/${f%%/*}_zipped/${out%.*}.zip"
    if [ ! -d "${out%/*}" ]; then
        mkdir -p "${out%/*}" || return
    fi
    zip --copy "$src" --out "$out" "$f" <&- || return
done

Eu adicionei LC_ALL=C à invocação de unzip porque seu formato de saída parece um pouco escasso em diferentes implementações e eu quero evitar pelo menos variantes de saída dependentes de localidade.

    
por David Foerster 24.11.2017 / 12:05
3

Isso deve ser capaz de fazer o que você quer:

#!/bin/bash

#Name of zip file
filename="$1"

# Check if valid zip file is passed
if file "$filename" | grep -wq "Zip archive data";
then    

        # List the contents of the zip file
        unzip -l "$filename" 

        # Make the destination folder
        # after checking they don't exist
        if [ ! -d Data_zipped ]; 
        then
                mkdir Data_zipped
        fi
        #make temporary folder
        #for extracted files
        tempdir=$(mktemp -d)            
        # Make temporary file to hold the filenames
        mysrc=$(mktemp)

        # Get the filesnames from the zip folder
        unzip -c Data.zip | cut -d" " -f3- | grep -E -o "[^Data/].*" | grep -Ev \(.zip\) | sed '/^\s*$/d' > "$mysrc"           

        while read -r var;
        do
                unzip -j "$filename" "Data/$var" -d "$tempdir/"                    
                # Get name of file from each read line
                zip Data_zipped/"$var".zip "$tempdir/$var"
                # remove the original file
                rm -rf "$tempdir/${var:?}"

        done < "$mysrc"           

else
        echo "Invalid file type: \"zip\" file required"
        exit 1
fi

Nota :

Estrutura de árvore usada:

Data
├── file_10.txt
├── file_1.txt
...
    
por George Udosen 23.11.2017 / 23:08
2

Você já pensou em procurar um sistema de arquivos com o zip-support ?

Isso basicamente expõe o arquivo zip como um diretório regular, do qual qualquer aplicativo pode abrir e ler arquivos, enquanto a biblioteca de fusíveis manipula os detalhes sujos de leitura e gravação do fluxo compactado.

No Ubuntu, você pode instalá-lo com sudo apt install fuse-zip

Depois de instalar o fusível-zip, você pode montar um arquivo zip com fuse-zip /path/to/some.zip mnt/ , onde mnt é um diretório vazio de sua escolha.

Após terminar, desmonte-o com fusermount -u mnt/ , onde mnt é o diretório onde você o montou.

fuse-zip até criará o zip na hora para você, se não for possível.

    
por vidarlo 23.11.2017 / 19:34
1

você pode descompactar os arquivos contidos em Data.zip, um por um: %código% e comprima-os.

mkdir Data_unzipped  
for i in 'seq 1 100'  # or whatever the number of your files is
do
  unzip Data.zip file_${i}.txt
  zip Data_unzipped/file_${i}.zip file_${i}.txt
  rm file_${i}.txt
done
    
por muclux 23.11.2017 / 19:40