Equivalente a "--strip-components = 1" di tar in unzip?


49

Ho uno script che estrae un file tar.gz in una sottocartella mysubfolder specificata :

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

Esiste un modo equivalente per farlo con un file zip?


2
Usa bsdtar
drizzt il

Risposte:


26

Come ha detto Mathias, unzipnon ha questa opzione, ma uno script bash da una riga può fare il lavoro.

Il problema è: l'approccio migliore dipende dal layout dell'archivio. Una soluzione che presuppone una singola directory di livello superiore fallirà miseramente se il contenuto si trova direttamente nella radice dell'archivio (pensare /a/foo /b/foo /fooe il caos dello stripping /ae /b).

E lo stesso fallimento accade con tar --strip-component. Non esiste una soluzione unica per tutti.

Quindi, per eliminare la directory principale, supponendo che ce ne sia una (e una sola):

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

Assicurati solo che i file / le directory di secondo livello non abbiano lo stesso nome del genitore di primo livello (ad esempio /foo/foo). Ma /foo/bar/fooe /foo/bar/barsono ok. Se lo fanno, o vuoi solo essere al sicuro, puoi usare una directory temporanea per l'estrazione:

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

Se stai usando Bash, puoi verificare se il livello più alto è una singola directory o non usi:

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

A proposito di Bash, dovresti accenderlo dotglobper includere file nascosti e puoi avvolgere tutto in un'unica, utile funzione:

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"
)

Ora inseriscilo nel tuo ~/.bashrco ~/.profilee non dovrai più preoccupartene. Usa semplicemente come:

unzip-strip sourcefile.zip mysubfolder

(nota che creerà automaticamente mysubfolderper te se non esiste)


Questo non si decomprimerà in una struttura di directory esistente come speravo (ho provato a usare. Al posto di mysubfolder). Ho finito per decomprimere (decomprimere zip-with-top-dir.zip) e quindi copiare (cp -rv extracted-top-zip-dir / *.).
catgofire,

4

Non ho trovato un'opzione simile nelle pagine del manuale perunzip , quindi temo che sia impossibile. :(

Tuttavia, (a seconda della situazione) potresti aggirare il problema. Ad esempio, se sei sicuro che l'unica directory di primo livello nel file zip sia denominata foo-seguita da un numero di versione, potresti fare qualcosa del genere:

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

Approccio gradevole, ma un po 'incompleto: avrai comunque foo * dir con l'intero contenuto estratto.
MestreLion,

Sì, non l'ho aggiunto rm -rf foo-*apposta perché è potenzialmente pericoloso. E se esistesse già una cartella denominata foo-bar? Si noti che l'estrazione viene eseguita all'interno della /tmpcartella, che viene svuotata automaticamente di tanto in tanto.
Mathias Bynens,

Ecco perché ho incatenato le operazioni utilizzando &&: un determinato passaggio si verifica solo se il passaggio precedente ha avuto esito positivo, quindi l'ultimo (il rm) viene eseguito solo se tutti i passaggi sono stati completati senza errori.
MestreLion,

2
Questo è anche il motivo per cui non si dovrebbe mai usare /tmp/some-hardcoded-folder-nameuna cartella temporanea, ma invece si dovrebbe usare mktempper questo: garantisce che non ci sarà tale cartella esistente. Controlla la mia risposta qui sotto.
MestreLion,

1

È possibile utilizzare -jper i percorsi spazzatura (non creare directory). Questo è consigliato solo per archivi a livello singolo piuttosto comuni. Gli archivi con strutture di directory multilivello verranno appiattiti - questo potrebbe persino portare a conflitti di nomi da estrarre per i file.

Dalla pagina man di decomprimere:

   -j     junk  paths.   The  archive's directory structure is not recreated; all files are deposited in the
          extraction directory (by default, the current one).
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.