Como descompactar, de-tar -xvf - desarquivar em uma pasta bagunçada?

14

Normalmente, desarquivo as coisas, $ mkdir newFolder; $ mv *.zip newFolder; $ cd newFolder; $unzip *.zipmas às vezes fico preguiçoso e faço isso em uma pasta arbitrária $ unzip *.zip, de vez em quando mexendo com outro conteúdo. Vou listar aqui alguns métodos - algumas versões de arquivo certamente possuem sinalizadores de baixa qualidade, enquanto outras são mais espartanas, estou mais interessado nesse último.

Algumas maneiras de desarquivar, existem outras?

  1. $ find . -anewer fileThatExistedBeforeUnarchieving -ok rm '{}' \;As fraquezas são que ele lista os *.zipdiretórios; portanto, você deve usar devagar -ok, devagar com muitas *.zipcorrespondências e, por algum motivo, parece não corresponder a tudo que foi extraído.

  2. Se houver uma pequena quantidade de arquivos extraídos, um por um, lento, pesado e propenso a erros.

  3. Quando quero ter certeza de que o conteúdo do arquivo é realmente uma pasta, às vezes verifico se $ unzip -l *.bsdfunciona pelo menos na versão descompactada do obsd.

Se você estiver se referindo a determinadas ferramentas de arquivamento, indique-as quando apropriado. Porém, mantenha as coisas simples - estou mais interessado nas maneiras de como você faz isso do que em uma única ferramenta.

Rui F Ribeiro
fonte
1
Consulte também Local de extração acidental - Como limpar?
Gilles 'SO- stop be evil'
Aqui está um script que eu uso para automatizar as mkdir; unzipcoisas, para que eu nunca tenha preguiça de fazê-lo! svn.mikelward.com/svn/scripts/untar
Mikel
2
Veja esta pergunta e respostas relacionadas: unix.stackexchange.com/questions/5123/…
alex

Respostas:

11

Por nome

Você pode gerar a lista de arquivos no arquivo morto e excluí-los, embora isso seja irritantemente complicado com arquivadores como descompactar ou 7z que não têm uma opção para gerar uma lista simples de nomes de arquivos. Mesmo com o tar, isso pressupõe que não há novas linhas nos nomes dos arquivos.

tar tf foo.tar | while read -r file; do rm -- "$file" done
unzip -l foo.zip | awk '
    p && /^ --/ {p=2}
    p==1 {print substr($0, 29)}
    /^ --/ {++p}
' | while …
unzip -l foo.zip | tail -n +4 | head -n -2 | while …  # GNU coreutils only
7z l -slt foo.zip | sed -n 's/^Path = //p' | while …  # works on tar.*, zip, 7z and more

Em vez de remover os arquivos, você pode movê-los para o destino pretendido.

tar tf foo.tar | while read -r file; do
  if [ -d "$file" ]; then continue; fi
  mkdir -p "/intended/destination/${file%/*}"
  mv -- "$file" "/intended/destination/$file"
done

Usando o FUSE

Em vez de depender de ferramentas externas, você pode (na maioria das unidades) usar o FUSE para manipular arquivos usando comandos comuns do sistema de arquivos.

Você pode usar o Fuse-zip para espiar um zip, extraí-lo com cp, listar seu conteúdo find, etc.

mkdir /tmp/foo.d
fuse-zip foo.zip /tmp/foo.d
## Remove the files that were extracted mistakenly (GNU/BSD find)
(cd /tmp/foo.d && find . \! -type d -print0) | xargs -0 rm
## Remove the files that were extracted mistakenly (zsh)
rm /tmp/foo.d/**(:"s~/tmp/foo.d/~~"^/)
## Extract the contents where you really want them
cp -Rp /tmp/foo.d /intended/destination
fusermount -u foo.d
rmdir foo.d

O AVFS cria uma exibição de toda a hierarquia de diretórios, na qual todos os arquivos possuem um diretório associado (mesmo nome com # alinhado no final) que parece conter o conteúdo do arquivo.

mountavfs
## Remove the files that were extracted mistakenly (GNU/BSD find)
(cd ~/.avfs/"$PWD/foo.zip#" && find . \! -type d -print0) | xargs -0 rm
## Remove the files that were extracted mistakenly (zsh)
rm ~/.avfs/$PWD/foo.zip\#/**/*(:"s~$HOME/.avfs/$PWD/foo.zip#~~"^/)
## Extract the contents where you really want them
cp -Rp ~/.avfs/"$PWD/foo.zip#" /intended/destination
umountavfs

Por data

Supondo que não tenha havido outra atividade na mesma hierarquia que sua extração, você pode informar os arquivos extraídos pelo ctime recente . Se você acabou de criar ou mover o arquivo zip, poderá usá-lo como ponto de corte; caso contrário, use ls -lctrpara determinar um tempo de corte adequado. Se você deseja ter certeza de não remover os zíperes, não há motivo para fazer qualquer aprovação manual: findé perfeitamente capaz de excluí-los. Aqui estão exemplos de comandos usando zsh ou find; note que as primárias -cmine -cnewernão estão no POSIX, mas existem no Linux (e outros sistemas com localização GNU), * BSD e OSX.

find . \! -name '*.zip' -type f -cmin -5 -exec rm {} +  # extracted <5 min ago
rm **/*~*.zip(.cm-6)  # zsh, extracted ≤5 min ago
find . -type f -cnewer foo.zip -exec rm {} +  # created or moved after foo.zip

Com o GNU find, FreeBSD e OSX, outra maneira de especificar o tempo de corte é criar um arquivo e usá-lo touchpara definir seu mtime para o tempo de corte.

touch -d … cutoff
find . -type f -newercm cutoff -delete

Em vez de remover os arquivos, você pode movê-los para o destino pretendido. Aqui está uma maneira de encontrar o GNU / * BSD / OSX, criando diretórios no destino, conforme necessário.

find . \! -name . -cmin -5 -type f -exec sh -c '
    for x; do
      mkdir -p "$0/${x%/*}"
      mv "$x" "$0/$x"
    done
  ' /intended/destination {} +

Equivalente a Zsh (quase: este reproduz toda a hierarquia de diretórios, não apenas os diretórios que conterão arquivos):

autoload zmv
mkdir -p ./**/*(/cm-3:s"|.|/intended/destination|")
zmv -Q '(**/)(*)(.cm-3)' /intended/destination/'$1$2'

Aviso, não testei a maioria dos comandos nesta resposta. Sempre revise a lista de arquivos antes de remover (execute echoprimeiro e, em seguida, rmse estiver ok).

Gilles 'SO- parar de ser mau'
fonte
Finalmente encontrei esse problema hoje. Como raiz! No final, eu usei uma combinação de "por nome" e "Por data"
phunehehe
1

Estou me sentindo idiota, de qualquer maneira, coçei a cabeça para escrever esse script quando tive um problema semelhante. Eu usei cpiocom a -itbandeira para obter uma lista de arquivos; você pode usar comandos equivalentes para outros arquivadores. A parte complicada é que o arquivo cpio é de um initrd e eu extraí para /, muitas pastas e arquivos têm o mesmo nome que em um sistema em funcionamento. Felizmente, o cpio não substituiu nenhum dos meus arquivos existentes. Uso uma verificação de tempo para garantir que não exclua nada que existia antes do comando errado.

#! /bin/sh

files=$(cpio -it < /mnt/temp/lglive.cpio)

for i in ${files}
do
    name=$(stat -c "%n" ${i})
    time=$(stat -c "%Y" ${i})
    # Time of the creation of the mess: 1296457595
    if [[ ${time} -gt 1296457590 && ${time} -lt 1296457600 ]]
    then
        if [[ -f ${name} ]]
        # If it is a file, it must have been created as part of the mess.
        then
            echo "rm ${name}"
        elif [[ -d ${name} ]]
        # If it is a directory, it may have been part of the mess
        # or maybe some files underneath it is created as part of the mess.
        then
            if [[ $(ls -A ${name}) ]]
            # If the directory contains something then don't delete it.
            then
                echo "${name} is not empty"
            # If the directory is empty then assume it is rubbish.
            else
                echo "rmdir ${name}"
            fi
        fi
    fi
done

echo "Files and directories still exist after the removal:"
for i in ${files}
do
    if [[ -e ${i} ]]
    then
        echo ${i}
    fi
done
phunehehe
fonte
0

Que tal alimentar a lista de arquivos no arquivo morto xargs rm?

Isso seria tar -tf tarbomb.tar | xargs rmou unzip --list zipbomb.zip | xargs rm.

alex
fonte
2
Os comandos fornecidos não funcionarão no caso geral, e isso é perigoso, pois você está removendo arquivos. xargsespera que sua entrada seja citada de uma maneira peculiar que findnão produza. Use xargs -I rm {}para que o xargs processe um item por linha. Para o comando descompactar, que implementação você tem? O Mine (Debian / Ubuntu) não possui --listapenas -le não apenas imprime nomes de arquivos, sendo necessário um processamento extra.
Gilles 'SO- stop be evil'
@Gilles: 1) sim, é perigoso, mas como presumivelmente substituímos os arquivos originais - eles já se foram. 2) eu não estava falando find. 3) você está certo unzip, não testei e parece não haver opção para listagens não decoradas. Não --listno meu Ubuntu também - eu apenas não testei.
24410 alex
Desculpe pela resposta, substitua tar -tpor find. Mas meus outros pontos permanecem. Existe um risco real de que o seu comando, conforme fornecido, exclua um arquivo não relacionado.
Gilles 'SO- stop be evil'
tar -tf tarbomb.tarimprimirá os nomes dos arquivos um por linha, para que você possa fazer tar -tf tarbomb.tar | while IFS=$'\n' read -r filename; do rm "$filename"; doneou algo semelhante.
Mikel
0

Não é exatamente o que você pediu, mas como usar um script "descompacte tudo" em vez de.

unzip *.zip

Dessa forma, a saída de cada arquivo entra em seu próprio diretório.

#!/bin/bash
for f in *.zip ; do unzip -n "$f" -d "${f/%zip/out}"; done
Johan
fonte
0

Eu uso a seguinte função no zsh:

ununzip () {
    rm -r $(unzip -l $1 | grep -v 'Archive:' | \
    grep '[/.]' | sed 's![^a-zA-Z]([a-zA-Z./])!\1!')
}

Ou seja, substituição de comando para remover todos os arquivos na saída limpa de unzip -l.

tar tvf poderia ser usado de maneira semelhante.

Edd Steel
fonte