CLI способ сжатия отдельных файлов, находящихся в данный момент в сжатой папке

У меня есть заархивированный файл Data.zip, который (если не распакован) содержит много файлов:

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

Я хочу получить команду CLI, чтобы превратить это в новую папку Data_zipped, которая содержит отдельного человека. файлы в Data.zip несжатые:

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

Но хитрость в том, что Data.zip содержит так много файлов (и они все вместе такие большие), что я не могу сначала распаковать Data.zip, а затем сжать отдельные файлы внутри него одним махом: все должно происходить «на лету»:

Для всех файлов в Data.zip/

  1. получить i-й файл
  2. сжать его в name_of_that_file.zip
  3. сохранить сжатый файл в новой папке Data_zipped

Как это сделать с помощью CLI?

Я изменил @ Сверхчистый скрипт Джорджа , чтобы лучше объяснить структуру папок:

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

Когда я запускаю его, я получаю (я использую токен Data.zip только с несколькими файлами в нем, но Вы поняли):

./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

Итак, я бы хотел, чтобы Level1_file.csv и другие файлы были заархивированы по отдельности. y (-> Level1_file.zip) и положить в папку.

Edit2;

Я закончил тем, что объединил ответы @ George's и @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
5
задан 24 November 2017 в 15:23

4 ответа

Вы можете использовать операцию «копирования» из zip(1) и некоторые искажения пути к файлу. Он имеет преимущество в том, что копирует сжатые потоки данных непосредственно в целевой архив без прерывистой распаковки.

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

Я добавил LC_ALL=C к вызову unzip, потому что его выходной формат выглядит немного нестабильным в разных реализациях, и я хочу, по крайней мере, избегать зависящих от локали вариантов вывода.

5
ответ дан 24 November 2017 в 15:23

Это должно быть в состоянии сделать то, что вы хотите:

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

Примечание :

Используется древовидная структура:

Data
├── file_10.txt
├── file_1.txt
...
3
ответ дан 24 November 2017 в 15:23

Рассматривали ли вы поиск файловой системы fuse с поддержкой zip ?

. В основном это представляет файл zip как обычный каталог, из которого любое приложение может открывать и читать файлы, в то время как библиотека fuse обрабатывает грязные детали чтения и записи сжатого потока.

В Ubuntu вы можете установить его с помощью sudo apt install fuse-zip

После установки fuse-zip вы можете смонтировать zip-файл с помощью fuse-zip /path/to/some.zip mnt/, где mnt - пустой каталог по вашему выбору.

После завершения размонтируйте его с помощью fusermount -u mnt/, где mnt - каталог, куда вы его смонтировали.

fuse-zip даже создаст молнию на лету для вас, если он не будет существовать.

2
ответ дан 24 November 2017 в 15:23

Вы можете разархивировать файлы, содержащиеся в Data.zip, один за другим: unzip Data.zip file1.txt и сжать их.

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
1
ответ дан 24 November 2017 в 15:23

Другие вопросы по тегам:

Похожие вопросы: