Создать каталог, если zip-архив содержит несколько файлов

8

Если архив содержит несколько файлов в корневом каталоге, я хотел бы создать каталог с именем по имени файла (без расширения). Если архив содержит только каталог, то я бы хотел просто распаковать его. Предположим, у меня есть следующий архив:

# file: withdir.zip
somedir/alpha
somedir/beta
somedir/gamma

Если я извлекаю его в текущем каталоге, я бы хотел, чтобы он был просто извлечен ( unzip withdir.zip):

somedir/alpha
somedir/beta
somedir/gamma

Теперь предположим следующий архив:

# file: nodir.zip
alpha
beta
gamma

Когда я запускаю, unzip nodir.zipя заканчиваю загромождать текущий каталог тремя файлами:

alpha
beta
gamma

Я бы лучше побежал unzip -d nodir nodir.zip:

nodir/alpha
nodir/beta
nodir/gamma

Если я использую наутилус и щелкну правой кнопкой мыши на «Извлечь здесь». Он ведет себя именно так, как и должен. Но, к сожалению, я не нашел ключ командной строки для unzipили 7zкоторые дают такое же поведение. Как этого добиться? Есть ли другие инструменты, которые я могу использовать вместо (без графического интерфейса)?

Marco
источник

Ответы:

7

Я хотел бы сделать что-то вроде этого (синтаксис zsh):

unz() (
  tmp=$(TMPDIR=. mktemp -d -- ${${argv[-1]:t:r}%.tar}.XXXXXX) || exit
  print -r >&2 "Extracting in $tmp"
  cd -- $tmp || exit
  [[ $argv[-1] = /* ]] || argv[-1]=../$argv[-1]
  (set -x; "$@"); ret=$?
  files=(*(ND[1,2]))
  case $#files in
    (0) print -r >&2 "No file created"
        rmdir -v "../$tmp";;
    (1) mv -v -- $files .. && rmdir -v ../$tmp;;
    (*) mv -vT ../$tmp ../$tmp:r;;
  esac && exit $ret
)

Это:

  1. создать каталог в любом случае
  2. запустить команду
  3. в зависимости от того, сколько файлов сгенерировала команда:
    • удалить этот каталог (если он не создал файл)
    • если он создал только один файл / dir, переместите его на один уровень вверх и откажитесь от нашего каталога
    • в противном случае попытайтесь удалить случайную строку из конца нашего временного каталога.

Таким образом, вы можете сделать:

unz unzip foo.zip
unz tar xf foo.tar.gz

Предполагается, что последний аргумент команды извлечения - это файл для извлечения. Также предполагается использование инструментов GNU для -vопций. В не-GNU системах вы можете удалить их и, возможно, выполнить регистрацию вручную. mv -Tтакже специфичен для GNU и должен mvпытаться делать только переименование.

Стефан Шазелас
источник
3

Как unzipи у 7zобоих есть переключатель для вывода в данном каталоге, вы можете создать простой скрипт, который проверяет, сколько файлов в корне архива , а затем добавляет переключатель , если это необходимо.

С 7z это проще, так как у него есть -sltпереключатель, который делает вывод более машиночитаемым. Для каждого файла в zip-файле вывод будет содержать Path = ...строку. Файлы в корне не должны содержать никаких /значений.

Простой скрипт, который я написал для распаковки файлов таким образом:

#!/bin/sh
for archive in "$@"; do
    # count files in root dir
    rootfiles=$(7z l -slt "${archive}" | grep -c 'Path = [^/]*$')

    # add -o switch, if more than one file in root
    # checks for >2, because path of the zip file itself is listed too
    if [ $rootfiles -gt 2 ]; then
        filename=${archive##*/}
        rootname=${filename%.*}
        opt="-o${rootname}"
    fi

    #unpack
    7z x "${opt}" "${archive}"
done

Изменить: скрипт теперь работает с zip тоже

crater2150
источник
Этот скрипт не работает должным образом. Он создает каталог withdirдля архива, withdir.zipхотя он содержит только один каталог в корне, потому что grep -c "Folder = -"возвращает 3.
Марко
Ах, папка, похоже, отличается для zip-файлов. Я поищу исправление
crater2150
@Marco: я изменил скрипт и протестировал его с помощью zip-файлов, теперь он создает папку только при необходимости
crater2150
3

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

Создать архив

patool create archive.zip somedirectory

Извлечь архив

patool extract archive.zip

Чтобы получить список поддерживаемых форматов, используйте patool formats.

Marco
источник
1

Вы также можете использовать unar , который по умолчанию создает каталог, содержащий два или более файлов верхнего уровня:

$ touch 1 2
$ zip a.zip 1 2
  adding: 1 (stored 0%)
  adding: 2 (stored 0%)
$ unzip -l a.zip
Archive:  a.zip
  Length     Date   Time    Name
 --------    ----   ----    ----
        0  04-29-14 10:56   1
        0  04-29-14 10:56   2
 --------                   -------
        0                   2 files
$ unar a.zip
a.zip: Zip
  1  (0 B)... OK.
  2  (0 B)... OK.
Successfully extracted to "a".
$ ls a
1 2

Добавить, -dчтобы всегда создавать содержащий каталог.

LRI
источник