LINUX.ORG.RU
ФорумAdmin

Можно ли без сложного sh скрипта отделить от массы группу zip файлов?

 , ,


0

1

Howdy, all!

Есть 1666 zip архивов. Большинство содержит по одному файлу, некоторые - по несколько. Как вывести список zip файлов, в которых находится больше одного файла (или наоборот - один) ?

В зависимости от ответа сформулирую общую задачу.

Спасибо ^_^/

$ touch file1 file2 file3
$ zip file1.zip file1 
  adding: file1 (stored 0%)
$ zip file2.zip file2
  adding: file2 (stored 0%)
$ zip file3.zip file1 file2 file3
  adding: file1 (stored 0%)
  adding: file2 (stored 0%)
  adding: file3 (stored 0%)
$ zip file4.zip file2 file3
  adding: file2 (stored 0%)
  adding: file3 (stored 0%)

$ find . -name '*.zip' | while read -r line; do zip -sf $line | awk -v file=$line '/Total/{if ($2 != "1"){print file}}'; done
./file4.zip
./file3.zip

$ zip -v
Copyright (c) 1990-2008 Info-ZIP - Type 'zip "-L"' for software license.
This is Zip 3.0 (July 5th 2008), by Info-ZIP.
...
Compiled with gcc FreeBSD Clang 14.0.5 (https://github.com/llvm/llvm-project.git llvmorg-14.0.5-0-gc12386ae247c) for Unix (FreeBSD 13.2-STABLE) on Mar 17 2023.
iron ★★★★★
()
Ответ на: комментарий от iron

Продолжу эту предложение в контексте предыдущей темы ТС.

Совершенно точно, можно поместить этот скрипт в «user menu» Midnight commandera. Или в «External panelize».

https://ibb.co/Bc1DbLF

И будет уже не так сложно.

andytux ★★★★★
()
Ответ на: комментарий от iron

Что-то на мох файлах всё сломалось с ошибками. Видимо дело в именах файлов, надо экранировать как-то..

k: fatal: cannot open file `Aces' for reading: Нет такого файла или каталога
awk: fatal: cannot open file `Aces' for reading: Нет такого файла или каталога
awk: cmd. line:1: (Europe).zip
awk: cmd. line:1:         ^ syntax error
awk: fatal: cannot open file `(USA,' for reading: Нет такого файла или каталога
awk: fatal: cannot open file `Volume' for reading: Нет такого файла или каталога
awk: fatal: cannot open file `(USA).zip' for reading: Нет такого файла или каталога
awk: fatal: cannot open file `(USA,' for reading: Нет такого файла или каталога
awk: fatal: cannot open file `(USA,' for reading: Нет такого файла или каталога
awk: fatal: cannot open file `(USA,' for reading: Нет такого файла или каталога
awk: fatal: cannot open file `Demonstration' for reading: Нет такого файла или каталога
awk: fatal: cannot open file `Disk' for reading: Нет такого файла или каталога
awk: cmd. line:1: Family,
awk: cmd. line:1:        ^ unexpected newline or end of string
awk: cmd. line:1: (USA,
awk: cmd. line:1:      ^ unexpected newline or end of string
awk: cmd. line:1: (USA,
awk: cmd. line:1:      ^ unexpected newline or end of string
awk: fatal: cannot open file `Studio' for reading: Нет такого файла или каталога
awk: fatal: cannot open file `&' for reading: Нет такого файла или каталога
awk: fatal: cannot open file `&' for reading: Нет такого файла или каталога
awk: fatal: cannot open file `&' for reading: Нет такого файла или каталога
awk: cmd. line:2: -
awk: cmd. line:2:  ^ unexpected newline or end of string
awk: fatal: cannot open file `Disk' for reading: Нет такого файла или каталога
awk: fatal: cannot open file `&' for reading: Нет такого файла или каталога
awk: fatal: cannot open file `Fighter' for reading: Нет такого файла или каталога
awk: cmd. line:1: (Europe).zip
awk: cmd. line:1:         ^ syntax error
hikikomori ★★★
() автор топика
Ответ на: комментарий от hikikomori
$ mv file4.zip "file4 (shit).zip"

$ find . -name '*.zip' | while read -r line; do zip -sf "$line" | awk -v file="$line" '/Total/{if ($2 != "1"){print file}}'; done
./file4 (shit).zip
./file3.zip
iron ★★★★★
()
Последнее исправление: iron (всего исправлений: 1)

unzip -l ‘some.zip’ | wc -l

оборачиваешь эту строку в цикл, а потом (или сразу) сортируешь в зависимости от величины wc -l свой вывод

ps. это мысли вслух, хотя тебе итак уже предложили более сложные вещи в треде

d00fy ★★★
()
Ответ на: комментарий от iron

Теперь ок, спасибо.Только работает довольно медленно, это нормально?

Суть задачи - распаковать архивы с одним файлом в текущую папку, а многофайловые архивы - каждый в свой каталог.

Но боюсь с такой скоростью скрипта, очень долго будет?

hikikomori ★★★
() автор топика
Ответ на: комментарий от hikikomori

Сначала распакуй каждый архив в отдельную папку. Потом пройдись по папкам и для папок с одним файлом перемести файл на уровень выше, удалив папку. Я бы так сделал.

vbr ★★★★
()
Ответ на: комментарий от hikikomori

Только работает довольно медленно, это нормально?

Это зависит от структуры папок по которой проходится find. Я написал самый универсальный вариант. Если файлы у тебя в одной папке, можно заменить find на for и должно быть существенно быстрее.

Суть задачи - распаковать архивы с одним файлом в текущую папку, а многофайловые архивы - каждый в свой каталог.

Многофайловые архивы содержат в себе каталог при распаковке? Т.е. файлы внутри архива в каталоге?

iron ★★★★★
()
Ответ на: комментарий от hikikomori

Суть задачи - распаковать архивы с одним файлом в текущую папку, а многофайловые архивы - каждый в свой каталог.

Я бы такое вообще без скриптов сделал. Средствами файлового менеджера распаковываешь все архивы каждый в свою папку, затем отсортировываешь по размеру и т.к. это папки то отсортируются они по кол-ву элементов. Выделяешь те где 1 объект и переносишь в отдельную папку, там делаешь поиск по *, выделяешь все файлы и вставляешь в общую папку.

Элементарщина же, скрипт будешь дольше писать чем руками делать, делов секунд на 10 если не считать время на распаковку архивов.

Khronos
()
Последнее исправление: Khronos (всего исправлений: 1)
Ответ на: комментарий от hikikomori

Суть задачи - распаковать архивы с одним файлом в текущую папку, а многофайловые архивы - каждый в свой каталог.

Я бы в таком случае никаких списков не получал. Распаковываешь в отдельный каталог, делаешь ls | wc -l на него, и если ровно один файл, переносишь куда надо, а каталог rmdir. Будет намного быстрее, чем два раза к 1666 файлам обращаться.

Хотя можно и получая список до распаковки, конечно, только работать всё же подряд с одним файлом, чтоб кэш ФС как надо работал. Как-то так:

#!/bin/sh
for i in *.zip; do
    if [ "$(unzip -qql "$i" 2> /dev/null | wc -l)" -gt 1 ]; then
        dirname="$(basename "$i" .zip)"
        mkdir -p "$dirname"
        unzip "$i" -d "$dirname"
    else
        # FIXME: что делать, если в двух однофайловых архивах имя файла одинаковое?
        unzip "$i"
    fi
done

Тут, в принципе, если HDD, то вся скорость упрётся в I/O в любом случае, как сам скрипт написан, будет влиять на уровне погрешности. На SSD можно воспользоваться parallel вместо цикла — должно быть быстрее по идее. Не уверен, впрочем, насколько.

На HDD можно ускорить это дело, читая последовательно не по алфавиту, а по физическому расположению с помощью fastwalk:

#!/bin/sh
fastwalk | grep '.zip' | while read -r i; do
    if [ "$(unzip -qql "$i" 2> /dev/null | wc -l)" -gt 1 ]; then
        dirname="$(basename "$i" .zip)"
        mkdir -p "$dirname"
        unzip "$i" -d "$dirname"
    else
        # FIXME: что делать, если в двух однофайловых архивах имя файла одинаковое?
        unzip "$i"
    fi
done

По идее, так должно быть быстрее

CrX ★★★★★
()
Последнее исправление: CrX (всего исправлений: 6)

unzip -l английским языком говорит, сколько там files

unzip -l file.zip | (head -n1; tail -n1) | tr -d ‘\n’

почти всё, что нужно. завернуть в find и дописывать в файл.

PS ещё проще zipinfo -h /usr/share/recoll/filters/rcllatinstops.zip | tr ‘\n’ ’ ’

mrjaggers
()
Последнее исправление: mrjaggers (всего исправлений: 4)

Напиши нормальный скрипт на Python, там есть батарейка zipfile вроде как из коробки. Думаю несмотря на медленность Python’а, оно отработает куда как быстрее чем все эти перенаправления архивов в пайпы и вызовы утилит на них.

Решение на Python будет как минимум не убогим write-only однострочником, который развалится если в имени файла будет пробел, кавычки и т. д., как вот это дерьмо: Можно ли без сложного sh скрипта отделить от массы группу zip файлов? (комментарий)

В этом решении не будет типичных проблем убогости Bash-подпорок.

EXL ★★★★★
()
Ответ на: комментарий от hikikomori

Там сразу файлы, без подкаталогов.

$ find . -name '*.zip' | while read -r line; do zip -sf "$line" | awk -v file="$line" -v dir=unpacked '/Total/{if ($2 != "1"){system("unzip -od "dir"/\""file"\" \""file"\"")}else{system("unzip -od "dir" \""file"\"")}}'; done

$ ls -lR unpacked/
total 1
-rw-r--r--  1 iron  wheel  0 29 авг.  13:21 file1
-rw-r--r--  1 iron  wheel  0 29 авг.  13:21 file2
drwxr-xr-x  2 iron  wheel  5 29 авг.  13:39 file3.zip
drwxr-xr-x  2 iron  wheel  4 29 авг.  13:39 file4 (shit).zip

unpacked/file3.zip:
total 1
-rw-r--r--  1 iron  wheel  0 29 авг.  13:21 file1
-rw-r--r--  1 iron  wheel  0 29 авг.  13:21 file2
-rw-r--r--  1 iron  wheel  0 29 авг.  13:21 file3

unpacked/file4 (shit).zip:
total 1
-rw-r--r--  1 iron  wheel  0 29 авг.  13:21 file2
-rw-r--r--  1 iron  wheel  0 29 авг.  13:21 file3
iron ★★★★★
()