Extraire l'archive tar sur place

14

J'ai un petit dilemme ici ...

J'avais besoin de déplacer environ 70 Go de fichiers d'un de mes serveurs à l'autre, j'ai donc décidé que les goudronner et envoyer l'archive serait le moyen le plus rapide.

Cependant, le serveur de réception ne dispose que de 5 Go d'espace après avoir reçu l'archive tar.

Existe-t-il un moyen d'extraire le goudron «en place»? Je n'ai pas besoin de conserver l'archive après son extraction, alors je me demandais s'il était possible de le faire.

Edit: Il convient de noter que l'archive a déjà été envoyée, et je voudrais éviter de renvoyer via une autre méthode.

lâche anonyme
la source

Réponses:

11
% tar czf - stuff_to_backup | ssh backupmachine tar xvzf -

cela se traduit par:

  • tar et compresser 'stuff_to_backup' en stdout
  • connectez-vous à «backupmachine» via ssh
  • exécutez «tar» sur la «machine de sauvegarde» et décompressez les éléments provenant de stdin

personnellement, j'utiliserais 'rsync over ssh' pour transférer les trucs parce que vous pouvez continuer à transférer des trucs si la connexion est interrompue:

% rsync -ar --progress -e 'ssh' 'stuff_to_backup' user@backupmachine:/backup/

qui transférera tout de 'stuff_to_backup' vers le dossier 'backup' sur la 'backupmachine'. si la connexion est rompue, répétez simplement la commande. si certains fichiers dans 'stuff_to_backup' changent, répétez le stuff, seule la différence sera transférée.

akira
la source
Voir ma question modifiée
lâche anonyme
@Charlie Somerville: oui, vous avez oublié la partie importante en premier lieu. :)
akira
6

Si l'autre machine a ssh, je vous recommanderais rsync comme une autre alternative qui n'utilise pas de fichier tar:

rsync -avPz /some/dir/ user@machine:/some/other/dir/

Et soyez prudent avec le leader /

Modifier la mise à jour

Eh bien, je vois comment c'est maintenant un excellent cornichon si vous n'êtes pas en mesure de le supprimer et de recommencer avec rsync. Je voudrais probablement essayer un extrait sélectif et le supprimer du goudron.

extrait sélectif:

$ tar xvf googlecl-0.9.7.tar googlecl-0.9.7/README.txt
googlecl-0.9.7/README.txt

suppression sélective:

$ tar --delete --file=googlecl-0.9.7.tar googlecl-0.9.7/README.txt

Cependant, il semble que vous passerez beaucoup de temps à coder un script pour cela ...

YuppieNetworking
la source
Voir ma question modifiée
lâche anonyme
Voir ma réponse modifiée ... bonne chance: - /
YuppieNetworking
Merci pour l'édition. Les fichiers sont en fait nommés avec des nombres, donc une boucle rapide pour bash pourrait bien faire l'affaire.
lâche anonyme
1
@Charlie Somerville: vous devrez peut-être commencer par les fichiers stockés à la fin du tar, sinon vous pourriez finir avec tar en créant une nouvelle archive ... alors, supprimez d'abord les fichiers de la fin du tar.
akira
5

Fondamentalement, ce dont vous avez besoin est la possibilité de canaliser le fichier dans tar et de "loper" le front au fur et à mesure.

Sur StackOverflow, quelqu'un a demandé comment tronquer un fichier à l'avant , mais il semble que ce ne soit pas possible. Vous pouvez toujours remplir le début du fichier avec des zéros d'une manière spéciale afin que le fichier devienne un fichier clairsemé , mais je ne sais pas comment faire. Nous pouvons cependant tronquer la fin du fichier. Mais tar doit lire l'archive en avant, pas en arrière.

Solution 1

Un niveau d'indirection résout chaque problème. Commencez par inverser le fichier sur place, puis lisez-le en arrière (ce qui entraînera la lecture du fichier d'origine vers l'avant) et tronquez la fin du fichier inversé au fur et à mesure.

Vous devrez écrire un programme (c, python, peu importe) pour échanger le début et la fin du fichier, morceau par morceau, puis diriger ces morceaux vers tar tout en tronquant le fichier un morceau à la fois. C'est la base de la solution 2 qui est peut-être plus simple à mettre en œuvre.

Solution 2

Une autre méthode consiste à diviser le fichier en petits morceaux sur place , puis à supprimer ces morceaux à mesure que nous les extrayons. Le code ci-dessous a une taille de bloc d'un mégaoctet, ajustez en fonction de vos besoins. Plus gros est plus rapide mais prendra plus d'espace intermédiaire lors du fractionnement et de l'extraction.

Fractionnez le fichier archive.tar:

archive="archive.tar"
chunkprefix="chunk_"
# 1-Mb chunks :
chunksize=1048576

totalsize=$(wc -c "$archive" | cut -d ' ' -f 1)
currentchunk=$(((totalsize-1)/chunksize))
while [ $currentchunk -ge 0 ]; do
    # Print current chunk number, so we know it is still running.
    echo -n "$currentchunk "
    offset=$((currentchunk*chunksize))
    # Copy end of $archive to new file
    tail -c +$((offset+1)) "$archive" > "$chunkprefix$currentchunk"
    # Chop end of $archive
    truncate -s $offset "$archive"
    currentchunk=$((currentchunk-1))
done

Canalisez ces fichiers dans tar (notez que nous avons besoin de la variable chunkprefix dans le deuxième terminal):

mkfifo fifo
# In one terminal :
(while true; do cat fifo; done) | tar -xf -
# In another terminal :
chunkprefix="chunk_"
currentchunk=0
while [ -e "$chunkprefix$currentchunk" ]; do
    cat "$chunkprefix$currentchunk" && rm -f "$chunkprefix$currentchunk"
    currentchunk=$((currentchunk+1))
done > fifo
# When second terminal has finished :
# flush caches to disk :
sync
# wait 5 minutes so we're sure tar has consumed everything from the fifo.
sleep 300
rm fifo
# And kill (ctrl-C) the tar command in the other terminal.

Puisque nous utilisons un tube nommé ( mkfifo fifo), vous n'avez pas besoin de diriger tous les morceaux à la fois. Cela peut être utile si vous manquez d'espace. Vous pouvez suivre les étapes suivantes:

  • Déplacez, par exemple, les derniers morceaux de 10 Go vers un autre disque,
  • Commencez l'extraction avec les morceaux que vous avez encore,
  • Une fois la while [ -e … ]; do cat "$chunk…; doneboucle terminée (deuxième terminal):
  • N'arrêtez PAS la tarcommande, ne supprimez PAS le fifo (premier terminal), mais vous pouvez exécuter sync, au cas où,
  • Déplacez certains fichiers extraits dont vous savez qu'ils sont terminés (tar n'est pas bloqué en attendant que les données finissent d'extraire ces fichiers) vers un autre disque,
  • Reculez les morceaux restants,
  • Reprenez l'extraction en exécutant à while [ -e … ]; do cat "$chunk…; donenouveau les lignes.

Bien sûr, tout cela est en haute voltige , vous voudrez d'abord vérifier que tout va bien sur une archive factice, car si vous faites une erreur, alors adieu les données .

Vous ne saurez jamais si le premier terminal ( tar) a réellement fini de traiter le contenu du fifo, donc si vous préférez, vous pouvez l'exécuter à la place, mais vous n'aurez pas la possibilité d'échanger de manière transparente des morceaux avec un autre disque:

chunkprefix="chunk_"
currentchunk=0
while [ -e "$chunkprefix$currentchunk" ]; do
    cat "$chunkprefix$currentchunk" && rm -f "$chunkprefix$currentchunk"
    currentchunk=$((currentchunk+1))
done | tar -xf -

Avertissement

Notez que pour que tout cela fonctionne, votre shell, votre queue et votre troncature doivent gérer correctement les entiers 64 bits (vous n'avez pas besoin d'un ordinateur 64 bits ni d'un système d'exploitation pour cela). Le mien le fait, mais si vous exécutez le script ci-dessus sur un système sans ces exigences, vous perdrez toutes les données dans archive.tar .

Et dans tous les cas, quelque chose d'autre ne va pas, vous perdrez toutes les données dans archive.tar de toute façon, alors assurez-vous d'avoir une sauvegarde de vos données.

Suzanne Dupéron
la source
0

Si vous avez des fichiers objets à déplacer, essayez de les supprimer. Cela permettra d'économiser une quantité considérable d'espace.

$ strip `find . -name "*.bin"`
kumar
la source