Equivalente ao “--strip-components = 1” do tar ao descompactar?


49

Eu tenho um script que extrai um arquivo tar.gz para um subdiretório especificado mysubfolder :

mkdir mysubfolder; tar --extract --file=sourcefile.tar.gz --strip-components=1 --directory=mysubfolder;

Existe alguma maneira equivalente de fazer isso com um arquivo zip?


2
Apenas use bsdtar
drizzt

Respostas:


26

Como Mathias disse, unzipnão tem essa opção, mas um script bash de uma linha pode fazer o trabalho.

O problema é: a melhor abordagem depende do layout do seu arquivo. Uma solução que pressupõe que um único diretório de nível superior falhe miseravelmente se o conteúdo estiver diretamente na raiz do arquivo morto (pense /a/foo /b/foo /foono caos de remover /ae remover /b).

E a mesma falha acontece com tar --strip-component. Não existe uma solução única para todos.

Assim, para retirar o directório raiz, assumindo que não é um (e única um):

unzip -d "$dest" "$zip" && f=("$dest"/*) && mv "$dest"/*/* "$dest" && rmdir "${f[@]}"

Apenas verifique se os arquivos / diretórios de segundo nível não têm o mesmo nome do pai de nível superior (por exemplo /foo/foo). Mas /foo/bar/fooe /foo/bar/barestá bem. Se sim, ou você apenas quer estar seguro, pode usar um diretório temporário para extração:

temp=$(mktemp -d) && unzip -d "$temp" "$zip" && mkdir -p "$dest" &&
mv "$temp"/*/* "$dest" && rmdir "$temp"/* "$temp"

Se você estiver usando o Bash, poderá testar se o nível superior é um único diretório ou não:

f=("$temp"/*); (( ${#f[@]} == 1 )) && [[ -d "${f[0]}" ]] && echo "Single dir!"

Por falar em Bash, você deve ativar dotglobpara incluir arquivos ocultos e pode agrupar tudo em uma única função útil:

unzip-strip() (
    local zip=$1
    local dest=${2:-.}
    local temp=$(mktemp -d) && unzip -d "$temp" "$zip" && mkdir -p "$dest" &&
    shopt -s dotglob && local f=("$temp"/*) &&
    if (( ${#f[@]} == 1 )) && [[ -d "${f[0]}" ]] ; then
        mv "$temp"/*/* "$dest"
    else
        mv "$temp"/* "$dest"
    fi && rmdir "$temp"/* "$temp"
)

Agora coloque isso no seu ~/.bashrcou ~/.profilee você nunca mais precisará se preocupar com isso. Basta usar como:

unzip-strip sourcefile.zip mysubfolder

(observe que ele será criado automaticamente mysubfolderse não existir)


Isso não será descompactado em uma estrutura de diretórios existente como eu esperava (tentei usar. No lugar da mysubfolder). Acabei descompactando (descompacte zip-with-top-dir.zip) e depois copiei (cp -rv extract-top-zip-dir / *.).
catgofire

4

Não consegui encontrar essa opção nas páginas de manual paraunzip , então temo que isso seja impossível. :(

No entanto, (dependendo da situação), você pode contornar isso. Por exemplo, se você tem certeza de que o único diretório de nível superior no arquivo zip é nomeado foo-seguido por um número de versão, você pode fazer algo assim:

cd /tmp
unzip /path/to/file.zip
cd foo-*
cp -r . /path/to/destination/folder

Boa abordagem, mas um pouco incompleta: você ainda terá foo * dir com todo o conteúdo extraído.
MestreLion

Sim, não adicionei rm -rf foo-*de propósito, pois isso é potencialmente perigoso. E se já houvesse uma pasta chamada foo-bar? Observe que a extração está sendo feita dentro da /tmppasta, que é esvaziada automaticamente de vez em quando.
Mathias Bynens 28/03

Por isso, encadeei operações usando &&: uma determinada etapa só acontece se a etapa anterior tiver sido bem-sucedida, portanto a última (a rm) será executada apenas se todas as etapas forem concluídas sem erro.
MestreLion

2
É também por isso que nunca se deve usar /tmp/some-hardcoded-folder-namecomo uma pasta temporária, mas sim mktemppara isso: garante que não haverá uma pasta existente. Confira minha resposta abaixo.
MestreLion 28/03

1

Você pode usar -jpara caminhos indesejados (não crie diretórios). Isso é recomendado apenas para arquivos de nível único comuns. Arquivos com estruturas de diretórios de vários níveis serão achatados - isso pode levar a conflitos de nomes para os arquivos extraídos.

Na página de manual do descompacte:

   -j     junk  paths.   The  archive's directory structure is not recreated; all files are deposited in the
          extraction directory (by default, the current one).
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.