Criar diretório se o arquivo zip contiver vários arquivos

8

Se um arquivo contém vários arquivos no diretório raiz, eu gostaria de criar um diretório com o nome do arquivo (sem extensão). Se um arquivo contém apenas um diretório, eu gostaria de simplesmente extraí-lo. Suponha que eu tenho o seguinte arquivo:

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

Se eu extraí-lo no diretório atual, gostaria de extraí-lo simplesmente ( unzip withdir.zip):

somedir/alpha
somedir/beta
somedir/gamma

Agora assuma o seguinte arquivo:

# file: nodir.zip
alpha
beta
gamma

Quando executo, unzip nodir.zipacabo bagunçando o diretório atual com os três arquivos:

alpha
beta
gamma

Prefiro correr unzip -d nodir nodir.zip:

nodir/alpha
nodir/beta
nodir/gamma

Se eu usar o nautilus e clique com o botão direito do mouse em "Extrair aqui". Ele se comporta exatamente como deveria. Mas, infelizmente, não encontrei uma opção de linha de comando para unzipou 7zque produza o mesmo comportamento. Como conseguir isso? Existem outras ferramentas que eu posso usar (sem GUI)?

Marco
fonte

Respostas:

7

Eu faria algo assim (sintaxe 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
)

Isso é:

  1. crie um diretório em qualquer caso
  2. execute o comando
  3. dependendo de quantos arquivos o comando gerou:
    • remova esse diretório (se não tiver criado nenhum arquivo)
    • se ele criou apenas um arquivo / dir, suba um nível e descarte nosso diretório
    • caso contrário, tente retirar a sequência aleatória do final do nosso diretório temporário.

Dessa forma, você pode fazer:

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

Ele pressupõe que o último argumento para o comando de extração seja o arquivo a ser extraído. Ele também assume ferramentas GNU para as -vopções. Em sistemas não-GNU, você pode removê-los e possivelmente fazer o log manualmente. mv -Ttambém é específico do GNU e deve forçar mva tentativa de renomear apenas.

Stéphane Chazelas
fonte
3

Como unzipe 7zambos têm uma opção para gerar saída para um determinado diretório, você pode criar um script simples, que verifique quantos arquivos estão na raiz do arquivo morto e, em seguida, adicione a opção, se necessário.

Com o 7z, isso é mais fácil, pois possui o -sltcomutador, o que torna a saída mais legível pela máquina. Para cada arquivo no zip, a saída conterá uma Path = ...linha. Os arquivos na raiz não devem conter nenhum /valor.

Um script simples que escrevi para descompactar arquivos dessa maneira:

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

Edit: script agora também funciona com zip

crater2150
fonte
Este script não funciona conforme o esperado. Ele cria um diretório withdirpara o arquivo withdir.zipmorto, embora contenha apenas um diretório na raiz porque grep -c "Folder = -"retorna 3.
Marco
ah, a pasta parece ser diferente para arquivos zip. Vou procurar uma correção
crater2150
@Marco: eu mudei o script e testei com arquivos zip, ele agora só cria a pasta quando necessário
crater2150
3

O patool lida com diferentes tipos de arquivos e cria um subdiretório, caso o arquivo contenha vários arquivos para evitar a confusão do diretório de trabalho com os arquivos extraídos.

Criar arquivo

patool create archive.zip somedirectory

Extrair arquivo

patool extract archive.zip

Para obter uma lista dos formatos suportados, use patool formats.

Marco
fonte
1

Você também pode usar unar , que cria um diretório que contém por padrão quando há dois ou mais arquivos de nível superior:

$ 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

Adicionar -dpara sempre criar um diretório contendo.

Lri
fonte