GNU/Linux >> Tutoriels Linux >  >> Linux

comment créer des archives multi tar pour un énorme dossier

J'ai écrit ce script bash pour le faire. Il forme essentiellement un tableau contenant les noms des fichiers à insérer dans chaque tar, puis démarre tar en parallèle sur chacun d'eux .Ce n'est peut-être pas le moyen le plus efficace, mais le travail sera fait comme vous le souhaitez. Je peux cependant m'attendre à ce qu'il consomme de grandes quantités de mémoire.

Vous devrez ajuster les options au début du script. Vous pouvez également modifier les options tar cvjf dans la dernière ligne (comme supprimer la sortie détaillée v pour les performances ou la modification de la compression j à z ,etc...).

Script

#!/bin/bash

# User configuratoin
#===================
files=(*.log)           # Set the file pattern to be used, e.g. (*.txt) or (*)
num_files_per_tar=5 # Number of files per tar
num_procs=4         # Number of tar processes to start
tar_file_dir='/tmp' # Tar files dir
tar_file_name_prefix='tar' # prefix for tar file names
tar_file_name="$tar_file_dir/$tar_file_name_prefix"

# Main algorithm
#===============
num_tars=$((${#files[@]}/num_files_per_tar))  # the number of tar files to create
tar_files=()  # will hold the names of files for each tar

tar_start=0 # gets update where each tar starts
# Loop over the files adding their names to be tared
for i in `seq 0 $((num_tars-1))`
do
  tar_files[$i]="$tar_file_name$i.tar.bz2 ${files[@]:tar_start:num_files_per_tar}"
  tar_start=$((tar_start+num_files_per_tar))
done

# Start tar in parallel for each of the strings we just constructed
printf '%s\n' "${tar_files[@]}" | xargs -n$((num_files_per_tar+1)) -P$num_procs tar cjvf

Explication

Tout d'abord, tous les noms de fichiers correspondant au motif sélectionné sont stockés dans le tableau files . Ensuite, la boucle for tranche ce tableau et forme des chaînes à partir des tranches. Le nombre de tranches est égal au nombre d'archives souhaitées. Les chaînes résultantes sont stockées dans le tableau tar_files . La boucle for ajoute également le nom de l'archive résultante au début de chaque chaîne. Les éléments de tar_files prendre la forme suivante (en supposant 5 fichiers/tarball) :

tar_files[0]="tar0.tar.bz2  file1 file2 file3 file4 file5"
tar_files[1]="tar1.tar.bz2  file6 file7 file8 file9 file10"
...

La dernière ligne du script, xargs est utilisé pour démarrer plusieurs tar processus (jusqu'au nombre maximum spécifié) où chacun traitera un élément de tar_files tableau en parallèle.

Tester

Liste des fichiers :

$ls

a      c      e      g      i      k      m      n      p      r      t
b      d      f      h      j      l      o      q      s

Tarballs générés :$ls /tmp/tar*tar0.tar.bz2 tar1.tar.bz2 tar2.tar.bz2 tar3.tar.bz2


Voici un autre script. Vous pouvez choisir si vous voulez précisément un million de fichiers par segment, ou précisément 30 segments. Je suis allé avec le premier dans ce script, mais le split mot-clé permet l'un ou l'autre choix.

#!/bin/bash
#
DIR="$1"        # The source of the millions of files
TARDEST="$2"    # Where the tarballs should be placed

# Create the million-file segments
rm -f /tmp/chunk.*
find "$DIR" -type f | split -l 1000000 - /tmp/chunk.

# Create corresponding tarballs
for CHUNK in $(cd /tmp && echo chunk.*)
do
    test -f "$CHUNK" || continue

    echo "Creating tarball for chunk '$CHUNK'" >&2
    tar cTf "/tmp/$CHUNK" "$TARDEST/$CHUNK.tar"
    rm -f "/tmp/$CHUNK"
done

Il y a un certain nombre de subtilités qui pourraient être appliquées à ce script. L'utilisation de /tmp/chunk. car le préfixe de la liste de fichiers devrait probablement être poussé dans une déclaration constante, et le code ne devrait pas vraiment supposer qu'il peut supprimer tout ce qui correspond à /tmp/chunk.* , mais je l'ai laissé ainsi comme une preuve de concept plutôt qu'un utilitaire raffiné. Si j'utilisais ceci, j'utiliserais mktemp pour créer un répertoire temporaire pour contenir les listes de fichiers.


Celui-ci fait exactement ce qui a été demandé :

#!/bin/bash
ctr=0;
# Read 1M lines, strip newline chars, put the results into an array named "asdf"
while readarray -n 1000000 -t asdf; do
  ctr=$((${ctr}+1));
# "${asdf[@]}" expands each entry in the array such that any special characters in
# the filename won't cause problems
  tar czf /destination/path/asdf.${ctr}.tgz "${asdf[@]}";
# If you don't want compression, use this instead:
  #tar cf /destination/path/asdf.${ctr}.tar "${asdf[@]}";
# this is the canonical way to generate output
# for consumption by read/readarray in bash
done <(find /source/path -not -type d);

readarray (en bash) peut également être utilisé pour exécuter une fonction de rappel, ce qui pourrait potentiellement être réécrit pour ressembler à :

function something() {...}
find /source/path -not -type d \
  | readarray -n 1000000 -t -C something asdf

GNU parallel pourrait être exploité pour faire quelque chose de similaire (non testé ; je n'ai pas parallel installé là où je suis donc je m'en sors) :

find /source/path -not -type d -print0 \
  | parallel -j4 -d '\0' -N1000000 tar czf '/destination/path/thing_backup.{#}.tgz'

Comme cela n'a pas été testé, vous pouvez ajouter le --dry-run arg pour voir ce qu'il va réellement faire. J'aime celui-ci le meilleur, mais tout le monde n'a pas parallel installée. -j4 lui fait utiliser 4 tâches à la fois, -d '\0' combiné avec find est -print0 lui fait ignorer les caractères spéciaux dans le nom de fichier (espaces, etc.). Le reste devrait être explicite.

Quelque chose de similaire pourrait être fait avec parallel mais je n'aime pas ça car ça génère des noms de fichiers aléatoires :

find /source/path -not -type d -print0 \
  | parallel -j4 -d '\0' -N1000000 --tmpdir /destination/path --files tar cz

Je ne connais pas [encore ?] un moyen de générer des noms de fichiers séquentiels.

xargs pourrait également être utilisé, mais contrairement à parallel il n'y a pas de moyen simple de générer le nom du fichier de sortie, vous finirez donc par faire quelque chose de stupide/hacky comme ceci :

find /source/path -not -type d -print0 \
  | xargs -P 4 -0 -L 1000000 bash -euc 'tar czf $(mktemp --suffix=".tgz" /destination/path/backup_XXX) "[email protected]"'

L'OP a dit qu'ils ne voulaient pas utiliser split ... J'ai pensé que cela semblait bizarre comme cat les rejoindra très bien ; cela produit un tar et le divise en morceaux de 3 Go :

tar c /source/path | split -b $((3*1024*1024*1024)) - /destination/path/thing.tar.

... et cela les décompresse dans le répertoire courant :

cat $(\ls -1 /destination/path/thing.tar.* | sort) | tar x

Linux
  1. Comment empaqueter des applications Python pour Linux

  2. Comment créer un répertoire partagé pour tous les utilisateurs sous Linux

  3. Créer une archive Tar d'un répertoire, à l'exception des fichiers cachés ?

  4. Comment puis-je créer un fichier dans chaque dossier ?

  5. Comment puis-je créer un fichier tar en plusieurs parties sous Linux ?

Comment créer une sauvegarde avec la commande tar sous Linux

Commande Tar sous Linux (créer et extraire des archives)

Comment créer un fichier Tar Gz

Comment décompresser les archives tar bz2 xz gz sous Linux

Comment créer un fichier Tar gz

Comment créer un contrôleur de domaine sous Linux pour AD